Tworzenie przyjaźni Pythona i Basha: biblioteki smart-env i Python-Shell

Dzień dobry wszystkim.

Dziś Python jest jednym z najczęściej używanych języków w zakresie tworzenia nie tylko samych produktów programowych, ale także zapewniania ich infrastruktury. W rezultacie wielu devopów, czy to z własnej woli, czy wbrew niemu, musiało nauczyć się nowego języka do późniejszego wykorzystania jako uzupełnienie starych, dobrych skryptów Bash. Bash i Python wyznają jednak odmienne podejście do pisania kodu i posiadają pewne cechy, przez co przeniesienie skryptów Bash na „język węża” okazuje się czasem zadaniem pojemnym i wcale nie trywialnym.

Aby ułatwić życie devopsom, stworzono i nadal tworzy się wiele przydatnych bibliotek i narzędzi w Pythonie. W tym artykule opisano dwie nowe biblioteki stworzone przez autora tego wpisu - inteligentne środowisko и powłoka Pythona - i zaprojektowany, aby odciążyć devopsa od konieczności zwracania dużej uwagi na zawiłości pracy z Pythonem, pozostawiając miejsce na ciekawsze zadania. Zakresem działania bibliotek są zmienne środowiskowe i uruchamianie narzędzi zewnętrznych.

Wszystkich zainteresowanych zapraszam do kota.

Nowe „rowery”?

Wydawałoby się, po co tworzyć nowe pakiety do całkiem zwyczajnych operacji? Co uniemożliwia Ci bezpośrednie użycie os.environ i subprocess.<wybranej metody lub klasy>?

Dowody na korzyść każdej z bibliotek przedstawię osobno.

biblioteka smart-env

Przed napisaniem własnego pomysłu warto skorzystać z Internetu i poszukać gotowych rozwiązań. Oczywiście istnieje ryzyko, że nie znajdziesz tego, czego potrzebujesz, ale jest to raczej „zdarzenie ubezpieczeniowe”. Z reguły takie podejście działa i pozwala zaoszczędzić dużo czasu i wysiłku.

Zgodnie z wynikami poszukiwania wyszło na jaw, co następuje:

  • istnieją pakiety, które faktycznie otaczają wywołania os.environ, ale jednocześnie wymagają szeregu odwracających uwagę działań (utworzenie instancji klasy, specjalne parametry w wywołaniach itp.);
  • Istnieją dobre pakiety, które jednak są ściśle powiązane z konkretnym ekosystemem (głównie frameworki internetowe, takie jak Django) i dlatego nie są wcale uniwersalne bez pliku;
  • rzadko zdarzają się próby zrobienia czegoś nowego. Na przykład, dodaj pisanie i jawnie analizuj wartości zmiennych, wywołując metody takie jak
    get_<typename>(var_name)

    Lub tu jeszcze jedno rozwiązanie, który jednak nie obsługuje obecnie zhańbionego Pythona 2 (który pomimo oficjalny RIP, nadal istnieją góry napisanego kodu i całe ekosystemy);

  • Istnieją rzemiosła uczniów, które z nieznanego powodu trafiły do ​​​​upstreamowego PyPI i stwarzają jedynie problemy z nazewnictwem nowych pakietów (w szczególności nazwa „smart-env” jest niezbędnym środkiem).

A tę listę można ciągnąć długo. Jednak powyższe punkty wystarczyły, abym podekscytował się pomysłem stworzenia czegoś wygodnego i uniwersalnego.

Wymagania jakie zostały postawione przed napisaniem smart-env:

  • Najprostszy schemat użycia
  • Łatwo konfigurowalna obsługa wpisywania danych
  • Kompatybilny z Pythonem 2.7
  • Dobre pokrycie kodu testami

Ostatecznie udało się to wszystko zrealizować. Oto przykład użycia:

from smart_env import ENV

print(ENV.HOME)  # Equals print(os.environ['HOME'])

# assuming you set env variable MYVAR to "True"

ENV.enable_automatic_type_cast()

my_var = ENV.MY_VAR  # Equals boolean True

ENV.NEW_VAR = 100  # Sets a new environment variable

Jak widać na przykładzie, aby pracować z nową klasą, wystarczy ją zaimportować (nie trzeba tworzyć instancji - pomijając dodatkową akcję). Dostęp do dowolnej zmiennej środowiskowej uzyskuje się poprzez odwołanie się do niej jako do zmiennej klasy ENV, co w istocie czyni tę klasę intuicyjnym opakowaniem dla natywnego środowiska systemu, jednocześnie zamieniając ją w możliwy obiekt konfiguracyjny dla niemal każdego systemu ( podobne podejście osiągnięto na przykład w Django, tylko tam obiektem konfiguracyjnym jest sam moduł/pakiet ustawień).

Włączanie/wyłączanie trybu obsługi automatycznego pisania odbywa się za pomocą dwóch metod - Enable_automatic_type_cast() i Disable_automatic_type_cast(). Może to być wygodne, jeśli zmienna środowiskowa zawiera serializowany obiekt podobny do JSON lub nawet tylko stałą logiczną (jednym z najczęstszych przypadków jest jawne ustawienie zmiennej DEBUG w Django poprzez porównanie zmiennej środowiskowej z „prawidłowymi” ciągami znaków). Ale teraz nie ma potrzeby jawnej konwersji ciągów znaków - większość niezbędnych akcji jest już osadzona w głębinach biblioteki i czeka tylko na sygnał do działania. 🙂 Ogólnie rzecz biorąc, pisanie działa w sposób przejrzysty i obsługuje prawie wszystkie dostępne wbudowane typy danych (zamrożone, złożone i bajty nie były testowane).

Wymóg obsługi Pythona 2 został wdrożony praktycznie bez wyrzeczeń (rezygnacja z pisania i niektórych „cukierków” najnowszych wersji Pythona 3), w szczególności dzięki wszechobecnej szóstce (w celu rozwiązania problemów związanych z wykorzystaniem metaklas ).

Ale są pewne ograniczenia:

  • Obsługa Pythona 3 oznacza wersję 3.5 i wyższą (ich obecność w Twoim projekcie wynika albo z lenistwa, albo z braku potrzeby ulepszania, bo ciężko znaleźć obiektywny powód, dla którego nadal jesteś na 3.4);
  • W Pythonie 2.7 biblioteka nie obsługuje deserializacji literałów zestawu. Opis tutaj. Ale jeśli ktoś ma ochotę to wdrożyć to zapraszam :);

Biblioteka posiada również mechanizm wyjątków na wypadek błędów analizy. Jeśli żaden z dostępnych analizatorów nie może rozpoznać ciągu znaków, wartość pozostaje ciągiem (raczej ze względu na wygodę i kompatybilność wsteczną ze zwykłą logiką działania zmiennych w Bash).

biblioteka powłoki Pythona

Teraz opowiem o drugiej bibliotece (pominę opis wad istniejących analogów - jest ona podobna do tej opisanej dla smart-env. Analogi - tutaj и tutaj).

Ogólnie pomysł wdrożenia i wymagania co do niego są podobne do tych opisanych dla smart-env, co widać na przykładzie:

from python_shell import Shell

Shell.ls('-l', '$HOME')  # Equals "ls -l $HOME"

command = Shell.whoami()  # Equals "whoami"
print(command.output)  # prints your current user name

print(command.command)  # prints "whoami"
print(command.return_code)  # prints "0"
print(command.arguments)  # prints ""

Shell.mkdir('-p', '/tmp/new_folder')  # makes a new folder

Pomysł jest taki:

  1. Pojedyncza klasa reprezentująca Basha w świecie Pythona;
  2. Każde polecenie Bash wywoływane jest jako funkcja klasy Shell;
  3. Parametry każdego wywołania funkcji są następnie przekazywane do odpowiedniego wywołania polecenia Bash;
  4. Każde polecenie wykonywane jest „tu i teraz” w momencie jego wywołania, tj. podejście synchroniczne działa;
  5. możliwy jest dostęp do wyniku polecenia na stdout, a także do jego kodu powrotu;
  6. Jeśli polecenia nie ma w systemie, zgłaszany jest wyjątek.

Podobnie jak w przypadku smart-env, istnieje wsparcie dla Pythona 2 (chociaż wymagane było trochę więcej ofiarnej krwi) i nie ma wsparcia dla Pythona 3.0-3.4.

Plany rozwoju biblioteki

Możesz teraz korzystać z bibliotek: obie są opublikowane na oficjalnym PyPI. Źródła są dostępne na Githubie (patrz poniżej).

Obie biblioteki będą rozwijane z uwzględnieniem opinii zebranych od zainteresowanych. A jeśli wymyślenie różnych nowych funkcji w smart-env może być trudne, to w Pythonie-Shell zdecydowanie jest coś jeszcze do dodania:

  • obsługa połączeń nieblokujących;
  • możliwość interaktywnej komunikacji z zespołem (praca ze stdin);
  • dodanie nowych właściwości (na przykład właściwość do odbierania danych wyjściowych ze stderr);
  • implementacja katalogu dostępnych poleceń (do użycia z funkcją dir());
  • itd.

referencje

  1. biblioteka smart-env: Github и PyPI
  2. biblioteka powłoki Pythona: Github и PyPI
  3. Kanał telegramu aktualizacje bibliotek

UPD 23.02.2020:
* Repozytoria zostały przeniesione, odpowiednie linki zostały zaktualizowane
* Wersja python-shell==1.0.1 jest przygotowywana do wydania 29.02.2020. Zmiany obejmują obsługę autouzupełniania poleceń i polecenia dir(Shell), uruchamianie poleceń z nieprawidłowym identyfikatorem Pythona oraz poprawki błędów.

Źródło: www.habr.com

Dodaj komentarz