Wyszukiwanie w witrynie

Przestań wpisywać te same 4 polecenia: Jak prosty skrypt Pythona oszczędza mi czas każdego dnia


Każdy programista ma rytuał przygotowawczy, zanim rozpocznie swój dzień. Mój był niekwestionowany przez prawie dwa lata - były to cztery polecenia terminala, wpisywane w tej samej kolejności każdego ranka. Nie wydawało się to problemem, dopóki ostatnio tego nie zmierzyłem; czas, pominięte kroki i późniejsze debugowanie wszystko się sumowały. Więc napisałem skrypt w Pythonie, aby je zastąpić, i stał się on najbardziej użyteczną rzeczą w moim środowisku programistycznym.

Cztery rozkazy

Dlaczego każda z tych komend była nie do negocjacji



Jeśli pracowałeś nad jakimkolwiek projektem w Pythonie w środowisku zespołowym, prawdopodobnie uruchomiłeś wszystkie cztery. Każdy z nich rozwiązał problem w moim przepływie pracy:

  • git status - To polecenie ujawniło niezatwierdzone lokalne zmiany przed pobraniem. Uruchomienie go najpierw zapobiegło chaotycznym sytuacjom scalania, które pojawiają się, gdy pobierasz zmiany nad pracę, którą zapomniałeś zmodyfikować.
  • git pull origin main - To synchronizuje moją lokalną gałąź z najnowszymi zmianami w repozytorium. Pominięcie tego oznacza, że mogę spędzić godziny pracując na przestarzałej bazie kodu i napotkać konflikty scalania, gdy trudniej je debugować.
  • pip install -r requirements.txt - uruchamiam to, aby zainstalować wszystkie zależności, które moi koledzy mogli dodać od mojego ostatniego uruchomienia. Jeśli to pominę, zwłaszcza po zmianie gałęzi, zazwyczaj kończę na ściganiu komunikatów o błędach, które wyglądają jak prawdziwe błędy, ale w rzeczywistości są po prostu brakującymi pakietami.
  • export DEBUG=true - To polecenie włącza szczegółowe logowanie i wyłącza niektóre zabezpieczenia przeznaczone wyłącznie dla środowiska produkcyjnego podczas lokalnego programowania. Każda nowa sesja terminala zaczyna się bez tego ustawienia, więc pominięcie polecenia export powodowało ciche błędy, które były trudne i frustrujące do zdiagnozowania.

Rodzimy skrypt i jego błędy

Początkowe rozwiązanie działało bez błędów, ale było niepoprawne w dwóch istotnych miejscach

Mój pierwszy instynkt był, aby owinąć wszystkie cztery w wywołania subprocess. Na początku wyglądało to schludnie, ale nie działało poprawnie.

## Don't do this
import subprocess

subprocess.run("git status", shell=True)
subprocess.run("git pull origin main", shell=True)
subprocess.run("pip install -r requirements.txt", shell=True)
subprocess.run("export DEBUG=true", shell=True) ## This does not make any change

Błąd 1: export DEBUG=true nic nie robi

Polecenie export jest poleceniem wbudowanym w powłokę. Kiedy jest wywoływane za pomocą subprocess.run(), działa wewnątrz procesu potomnego, który kończy się w momencie zwrócenia wywołania. Zmienne środowiskowe, które ustawiłem w procesie potomnym, nigdy nie dotarły do powłoki nadrzędnej. Polecenie wykonało się, zgłosiło sukces, a moja sesja terminala pozostała niezmieniona, bez zwracania błędu ani ostrzeżenia.

Błąd 2: Brak obsługi błędów oznaczał ciche awarie

subprocess.run() nie zgłasza wyjątku, gdy polecenie zakończy się niepowodzeniem, zwracało kod wyjścia różny od zera, który musiałem sprawdzić samodzielnie. W natywnym skrypcie, jeśli git pull nie powiedzie się z powodu problemów z siecią, skrypt kontynuuje działanie, instaluje pakiety na przestarzałej bazie kodu i zaczynasz dzień nie mając pojęcia, że coś poszło nie tak.

Skrypt, który działał

Mój drugi skrypt obsługiwał błędy, działał poprawnie i robi dokładnie to, co twierdzi






Dodałem alias, który sprawia, że uruchamianie skryptu jest jeszcze krótsze, za pomocą polecenia dev. Oto wersja, którą uruchamiam teraz, z obsługą wszystkich czterech zadań poprawnie i z wbudowaną obsługą błędów od samego początku.

import subprocess
import os
import sys

# The central helper - every command runs through here.
# Prints what it's doing, captures the output and exits with debugging information on failure
def run(command, description): 
    print(f"-> {description}...")
    result = subprocess.run(
        command, shell=True, capture_output=True, text=True
    )
    if result.returncode != 0:
       # stop immediately and show error
       print(f"  FAILED: {result.stderr.strip()}")
        sys.exit(1)
    print("  Done")
    return result

# Checks for uncommitted changes before pulling.
# Warns instead of blocking — the developer decides what to do.
def check_repo_state():
    result = run("git status --porcelain", "Checking repo state")
    if result.stdout.strip():
        print("  Warning: uncommitted changes detected.")

# Syncs the local branch with the remote.
# Halts the script if the pull fails (e.g. no network connection).
def pull_latest():
    run("git pull origin main", "Pulling latest from main")


# Installs any new dependencies since the last session.
# -q suppresses already-satisfied output so real changes are easy to spot.
def install_dependencies():
    run(
        "pip install -r requirements.txt -q",
        "Installing/verifying dependencies"
    )

def start_server():
    print("-> Starting dev server (DEBUG=true)...")
    # Copy the current environment so we don't mutate os.environ globally
    env = os.environ.copy()
    # Set DEBUG here instead of using export — variables set in a subprocess
    # don't persist to the parent shell, so this is the correct approach.
    env["DEBUG"] = "true"
    # Pass the modified environment directly to the server process.
    # DEBUG stays alive for the full lifetime of the server.
    subprocess.run(["python", "manage.py", "runserver"], env=env)


# Runs all steps in the correct order.
# If any step fails, the script stops before reaching the next one.
def main():
 print("\n  Starting dev environment...\n")
    check_repo_state()
    pull_latest()
    install_dependencies()
    start_server()


if __name__ == "__main__":
    main()

Co się zmieniło po codziennym stosowaniu tego

Pominięte kroki zniknęły, błędy stały się bardziej zrozumiałe, a wdrożenie stało się prostym jednowierszowym procesem

Najbardziej nieoczekiwaną korzyścią było wprowadzenie nowych osób do pracy. Kilka tygodni po napisaniu skryptu przygotowywałem dewelopera, który był nowy w projekcie. Zamiast przeprowadzać go przez sekwencję konfiguracji, udostępniłem mu skrypt, i był gotowy do pracy w mniej niż minutę.

Błędy stały się również łatwiejsze do zdiagnozowania. Przed skryptem, zapomniane polecenie pip install pojawiało się jako ModuleNotFoundError głęboko w kodzie, co sprawiało, że spędzałem trochę czasu na debugowaniu. Teraz, jeśli instalacja zawiedzie, skrypt zatrzymuje się natychmiast i dokładnie wyświetla, co poszło nie tak.


Najmniejsza automatyzacja jest często najbardziej wartościowa

Twój skrypt nie musi być imponującym dziełem inżynierii, musi po prostu ułatwiać twoją pracę. Jeśli codziennie wykonujesz jakąkolwiek sekwencję poleceń, to jej automatyzacja z pewnością jest warta stworzenia.

Powiązane artykuły