Kas yra Typer ir kodėl jis vertas dėmesio
Jei kada nors bandėte sukurti komandų eilutės (CLI) aplikaciją Python kalba, greičiausiai susidūrėte su argparse arba click bibliotekomis. Jos veikia, bet dažnai reikalauja nemažai boilerplate kodo ir nėra itin intuityvios. Čia į sceną įžengia Typer – palyginti nauja biblioteka, sukurta to paties kūrėjo, kuris mums padovanojo FastAPI.
Typer filosofija paprasta: panaudoti Python type hints (tipo užuominas) maksimaliai efektyviai, kad CLI aplikacijų kūrimas būtų greitas, paprastas ir malonus. Jei esate dirbę su FastAPI, iš karto pajusite pažįstamą stilių – tas pats elegantiškas požiūris, tik komandų eilutės aplikacijoms.
Biblioteka automatiškai generuoja pagalbos pranešimus, validuoja įvestį ir net sukuria interaktyvius autocomplete funkcionalumus. Viskas, ko jums reikia – parašyti paprastas Python funkcijas su tipo anotacijomis. Typer pasirūpina visu likusiu darbu.
Pirmieji žingsniai su Typer
Pradėkime nuo paprasčiausio pavyzdžio. Įdiekite Typer naudodami pip:
„`
pip install typer
„`
Dabar sukurkime pačią paprasčiausią CLI aplikaciją:
„`python
import typer
def main(name: str):
print(f”Labas, {name}!”)
if __name__ == „__main__”:
typer.run(main)
„`
Taip, tai viskas. Išsaugokite šį kodą kaip `hello.py` ir paleiskite:
„`
python hello.py Jonas
„`
Gausite: „Labas, Jonas!”. Bet kas nutinka, jei paleisime `python hello.py –help`? Typer automatiškai sugeneravo pagalbos tekstą su visais parametrais. Jei pamirštate nurodyti vardą, gausite aiškų klaidos pranešimą.
Palyginimui, su argparse tam pačiam rezultatui prireiktų bent 10-15 eilučių kodo su visais parser.add_argument() iškvietimais. Typer tiesiog „supranta” ką norite padaryti iš funkcijos signatūros.
Parametrų valdymas ir numatytosios reikšmės
Realios CLI aplikacijos retai apsiriboja vienu parametru. Typer puikiai tvarko įvairius parametrų tipus, numatytąsias reikšmes ir net sudėtingesnius scenarijus.
„`python
import typer
def process_file(
filename: str,
verbose: bool = False,
output_format: str = „json”,
max_lines: int = 100
):
if verbose:
print(f”Apdorojamas failas: {filename}”)
print(f”Formatas: {output_format}”)
print(f”Maksimalus eilučių skaičius: {max_lines}”)
# Jūsų logika čia
print(f”Failas {filename} apdorotas!”)
if __name__ == „__main__”:
typer.run(process_file)
„`
Šią aplikaciją galite paleisti įvairiais būdais:
„`
python process.py data.txt
python process.py data.txt –verbose
python process.py data.txt –output-format csv –max-lines 500
„`
Atkreipkite dėmesį, kaip Typer automatiškai konvertuoja `output_format` į `–output-format` komandų eilutėje. Tai standartinė CLI konvencija, ir jums nereikia apie tai galvoti.
Boolean parametrai automatiškai tampa flag’ais – jei nurodote `–verbose`, jis tampa `True`, jei ne – lieka `False`. Typer taip pat automatiškai validuoja tipus – jei bandysite perduoti tekstą vietoj skaičiaus `max_lines` parametrui, gausite aiškų klaidos pranešimą.
Kelių komandų aplikacijos
Daugelis CLI įrankių turi kelias komandas (pvz., git turi `git commit`, `git push`, `git pull`). Typer tai padaro itin paprastai naudojant `typer.Typer()` objektą:
„`python
import typer
app = typer.Typer()
@app.command()
def create(name: str, template: str = „basic”):
„””Sukuria naują projektą”””
print(f”Kuriamas projektas: {name}”)
print(f”Naudojamas šablonas: {template}”)
@app.command()
def delete(name: str, force: bool = False):
„””Ištrina projektą”””
if force:
print(f”Projektas {name} ištrintas be patvirtinimo”)
else:
confirm = typer.confirm(f”Ar tikrai norite ištrinti {name}?”)
if confirm:
print(f”Projektas {name} ištrintas”)
else:
print(„Atšaukta”)
@app.command()
def list_projects():
„””Parodo visus projektus”””
print(„Projektų sąrašas:”)
print(„- Projektas 1”)
print(„- Projektas 2”)
if __name__ == „__main__”:
app()
„`
Dabar turite pilnavertę CLI aplikaciją su trimis komandomis:
„`
python project.py create mano-projektas
python project.py delete senas-projektas –force
python project.py list-projects
„`
Docstring’ai, kuriuos parašėte funkcijose, automatiškai tampa komandų aprašymais pagalbos tekste. Paleiskite `python project.py –help` ir pamatysite gražiai suformatuotą pagalbą su visomis komandomis ir jų aprašymais.
Pažangesnės galimybės: Options ir Arguments
Typer skiria du parametrų tipus: Arguments (pozicinius argumentus) ir Options (opcijas su flag’ais). Pagal nutylėjimą, parametrai be numatytųjų reikšmių tampa argumentais, o su numatytosiomis – opcijomis. Bet kartais norite tikslesnės kontrolės:
„`python
import typer
from typing import Optional
def deploy(
environment: str = typer.Argument(…, help=”Aplinka: dev, staging, production”),
version: str = typer.Option(„latest”, „–version”, „-v”, help=”Versija”),
dry_run: bool = typer.Option(False, „–dry-run”, help=”Testuoti be realaus deployment’o”),
config_file: Optional[str] = typer.Option(None, „–config”, „-c”, help=”Konfigūracijos failas”)
):
print(f”Deployment’as į {environment}”)
print(f”Versija: {version}”)
if dry_run:
print(„DRY RUN režimas – niekas nebus pakeista”)
if config_file:
print(f”Naudojamas config: {config_file}”)
if __name__ == „__main__”:
typer.run(deploy)
„`
`typer.Argument(…)` trijų taškų sintaksė reiškia, kad parametras yra privalomas. `typer.Option()` leidžia nurodyti trumpuosius flag’us (pvz., `-v` vietoj `–version`), pridėti pagalbos tekstus ir nustatyti numatytąsias reikšmes.
Galite naudoti ir `Optional` tipo užuominą iš `typing` modulio, kad parodytumėte, jog parametras gali būti `None`. Typer tai supranta ir tinkamai apdoroja.
Interaktyvumas ir vartotojo įvestis
Viena iš Typer stipriųjų pusių – integruoti interaktyvūs elementai. Kartais CLI aplikacijai reikia patvirtinimo, slaptažodžio ar pasirinkimo iš sąrašo:
„`python
import typer
def setup_database():
db_name = typer.prompt(„Įveskite duomenų bazės pavadinimą”)
db_password = typer.prompt(
„Įveskite slaptažodį”,
hide_input=True,
confirmation_prompt=True
)
use_ssl = typer.confirm(„Ar naudoti SSL?”)
db_type = typer.prompt(
„Pasirinkite DB tipą”,
type=typer.Choice([„postgresql”, „mysql”, „sqlite”])
)
print(f”\nKonfigūracija:”)
print(f”Pavadinimas: {db_name}”)
print(f”Tipas: {db_type}”)
print(f”SSL: {‘Taip’ if use_ssl else ‘Ne’}”)
if typer.confirm(„Ar tęsti su šia konfigūracija?”):
print(„Konfigūracija išsaugota!”)
else:
print(„Atšaukta”)
if __name__ == „__main__”:
typer.run(setup_database)
„`
`typer.prompt()` leidžia prašyti įvesties su validacija, `typer.confirm()` – gauti taip/ne atsakymą, o `typer.Choice()` – apriboti galimas reikšmes. Slaptažodžiams galite naudoti `hide_input=True`, kad simboliai nebūtų rodomi ekrane.
Tai puikiai tinka setup skriptams, deployment įrankiams ar bet kokiai aplikacijai, kuriai reikia interakcijos su vartotoju.
Spalvos, progress bar’ai ir gražus output
CLI aplikacijos nebūtinai turi būti nuobodžios. Typer naudoja Rich biblioteką po gaubtu, todėl galite lengvai pridėti spalvų ir formatavimo:
„`python
import typer
import time
def process_data(items: int = 100):
typer.echo(„Pradedamas duomenų apdorojimas…”)
with typer.progressbar(range(items), label=”Apdorojama”) as progress:
for item in progress:
# Simuliuojame darbą
time.sleep(0.02)
typer.secho(„✓ Sėkmingai apdorota!”, fg=typer.colors.GREEN, bold=True)
typer.secho(„Įspėjimas: kai kurie įrašai praleisti”, fg=typer.colors.YELLOW)
typer.secho(„Klaida: nepavyko prisijungti prie išorinės API”, fg=typer.colors.RED)
if __name__ == „__main__”:
typer.run(process_data)
„`
`typer.progressbar()` automatiškai sukuria gražų progress bar’ą su procentais ir laiko įverčiu. `typer.secho()` (styled echo) leidžia pridėti spalvų ir formatavimo – puikus būdas išskirti svarbius pranešimus, įspėjimus ar klaidas.
Tai ypač naudinga ilgai trunkančioms operacijoms – vartotojai mato, kad kažkas vyksta, ir gali įvertinti, kiek dar laukti.
Realaus pasaulio patarimai ir best practices
Dirbant su Typer realiuose projektuose, išmokau kelių dalykų, kurie gali sutaupyti laiko ir nervų.
**Struktūrizuokite didesnes aplikacijas**. Jei turite daug komandų, neskaidykite jų į atskirus failus ir naudokite `add_typer()` metodą:
„`python
# commands/users.py
import typer
user_app = typer.Typer()
@user_app.command()
def create(name: str):
print(f”Vartotojas {name} sukurtas”)
@user_app.command()
def delete(name: str):
print(f”Vartotojas {name} ištrintas”)
# main.py
import typer
from commands.users import user_app
app = typer.Typer()
app.add_typer(user_app, name=”user”)
if __name__ == „__main__”:
app()
„`
**Naudokite Enum tipus pasirinkimams**. Vietoj paprastų string’ų, Enum’ai suteikia geresnę tipo saugą:
„`python
from enum import Enum
import typer
class Environment(str, Enum):
dev = „dev”
staging = „staging”
production = „production”
def deploy(env: Environment):
print(f”Deployment’as į {env.value}”)
„`
**Validuokite sudėtingesnius parametrus**. Nors Typer automatiškai validuoja tipus, kartais reikia papildomos logikos:
„`python
def create_user(
email: str = typer.Argument(…),
age: int = typer.Option(…)
):
if „@” not in email:
typer.echo(„Neteisingas email formatas”, err=True)
raise typer.Exit(code=1)
if age < 18: typer.echo("Vartotojas turi būti pilnametis", err=True) raise typer.Exit(code=1) print(f"Vartotojas sukurtas: {email}") ``` **Testuokite CLI aplikacijas**. Typer puikiai veikia su pytest: ```python from typer.testing import CliRunner import pytest runner = CliRunner() def test_create_command(): result = runner.invoke(app, ["create", "test-project"]) assert result.exit_code == 0 assert "Kuriamas projektas: test-project" in result.stdout ```
Kai viskas susideda į vieną paveikslą
Typer tikrai pakeičia CLI aplikacijų kūrimo patirtį Python ekosistemoje. Jei anksčiau vengiau kurti komandų eilutės įrankius dėl argparse sudėtingumo, dabar tai tampa malonumu. Type hints, kuriuos ir taip turėčiau naudoti geroje praktikoje, čia tampa funkcionalumo pagrindu.
Biblioteka puikiai tinka tiek mažiems utility skriptams, tiek dideliems įrankiams su daugybe komandų. Automatinis pagalbos generavimas, interaktyvūs elementai, spalvos – visa tai iš dėžės, be papildomo kodo. O jei esate FastAPI gerbėjas, čia rasite tą patį elegantišką API dizainą.
Pradėkite nuo paprasto skripto, pridėkite kelias komandas, išbandykite interaktyvius elementus. Greitai pastebėsite, kad CLI aplikacijų kūrimas nebėra nuobodus uždavinys, o greičiau malonus procesas. Ir kas žino – galbūt jūsų kitas projektas bus būtent ta CLI aplikacija, kurios jums seniai reikėjo, bet vis atidėliojote.
