Hot Reloading w Pythonie

17

Cześć wszystkim,
Jakbyscie byli zainteresowani tematem hot reloadingu to polecam moja paczkę reloadium.
https://github.com/reloadware/reloadium

Umożliwia ona modyfikację kodu w trakcie działania aplikacji.
example_small.gif
Napisałem też plugin do PyCharma
https://plugins.jetbrains.com/plugin/18509-reloadium

Jestem ciekaw co o tym myślicie.

1

Hmm, ciekawe sprawdzę dziś, ale szczerze nie widzę zastosowania dla większych projektów.

4

@veneficus

Wręcz przeciwnie, zmiana kodu w locie jest jedną z najużyteczniejszych rzeczy przy debugowaniu i im większy projekt, im więcej trzeba pozmieniać aby wprowadzić system w określony stan tym bardziej się taki feature przydaje

@Kwazar90:

A jak wygląda wsparcie dla przeskakiwania do różnych linii kodu? np. z 1 do 3, wykonanie 4, dopisanie 5 i jej wykonanie, a na końcu powrót do 1?

1

@1a2b3c4d5e: Tak te funkcje sa wspierane. Dodatkowo jak uzytkownik sie pomyli mozna poprawic bledy jak ponizej:

image

1

Mógłbyś tak high levelowo opisać jak to działa?

3

@1a2b3c4d5e: Kod nowego modulu jest wykonywany w sandboxie po czym sa wykrywane i dodawane zmiany. Jezeli zmiana jest w trakcie debugowania jak pokazane powyzej to dodatkowo funkcja w ktorej jest debugger jest restartowana.

1

Nie widzę listy wspieranych urządzeń na GH, Python 3.10, OSX, Pycharm professional, Nie ma wsparcia dla wszystkiego?
screenshot-20220416205237.png

0

@veneficus: Czy to jest OSX ARM64? Wszystkie systemy sa wspierane oprocz tego wlasnie. Aktualnie nie da sie zbudowac paczek na ten system na github actions.
I racja, musze to dodac na githubie.

2

A masz jakiś sensowny przykład kiedy to by miało sens? Jakiś scenariusz?

0

@TomRiddle:

Puszczam kod który wykonuje SQLa i poleciał wyjątek, ale jako że nie chce mi się przygotowywać danych, ani aby odpalał się wcześniejszy kod jeszcze raz

void DoSomething(a,b,c)
{
	try
	{
		sql("SELEKT *", a,b,c);
	}
	catch (Exception ex)
	{
		
	}
}

to w obsłudze wyjątku dodałem linijkę która wykonuje tą samą funkcję jeszcze raz i przekazuje tam parametry

void DoSomething(a,b,c)
{
	try
	{
		sql("SELEKT *", a,b,c);
	}
	catch (Exception ex)
	{
		DoSomething(a,b,c);
	}
}

i teraz gdy jestem tu

void DoSomething(a,b,c)
{
	try
	{ <------------------- jestem tu
		sql("SELEKT *", a,b,c);
	}
	catch (Exception ex)
	{
		DoSomething(a,b,c);
	}
}

to zmieniam to zapytanie, puszczam niech wykona

void DoSomething(a,b,c)
{
	try
	{
		sql("SELECT *", a,b,c);
	}  <------------------- jestem tu
	catch (Exception ex)
	{
		DoSomething(a,b,c);
	}
}

i teraz usuwam to co dodałem

void DoSomething(a,b,c)
{
	try
	{
		sql("SELEKT *", a,b,c);
	}  <------------------- jestem tu
	catch (Exception ex)
	{
 
	}
}
1

Niby pomysł spoko, aczkolwiek trochr nie kumam czemu miałbym nie zeminic kodu i nie zrobić restart. Chyba tylko tym że mam już breakpoint we frameie, ale nawigacja po stacku wywołań jak ktoś umie w debugger to nie jest jakiś super trudna.

Także dla mnie pomysł fajny, jeśli faktycznie to by działało bez zarzutu i nie robiło jakichś cyrków, to spoko. Fajny bajer. Ale nie widzę co by to narzędzie umiało czego restart sesji by nie umiał, trochę bardziej wygodne tylko.

3

@TomRiddle bo np. dojście do sytuacji w danym miejscu kosztuje dużo czasu ;) Np. próbujesz striggerować jakiś bardzo specyficzny bug gdzie setup jest skomplikowany i restart oznacza że stracisz kolejne pół godziny (ot powiedzmy jakiś heisenbug wynikający z concurrency który pojawia się raz na pół godziny mielenia requestów)

1
Shalom napisał(a):

@TomRiddle bo np. dojście do sytuacji w danym miejscu kosztuje dużo czasu ;) Np. próbujesz striggerować jakiś bardzo specyficzny bug gdzie setup jest skomplikowany i restart oznacza że stracisz kolejne pół godziny (ot powiedzmy jakiś heisenbug wynikający z concurrency który pojawia się raz na pół godziny mielenia requestów)

A nawet jeśli już miałbyś już znaleźć takiego buga, to czemu miałbyś nie użyć wtedy "watch" z debuggera albo "evaluate expression"? Co takiego ma zaprezentowane rozwiązanie, czego już nie mają debuggery - poza tym, że może to jest kapkę lepszy interfejs, że w kodzie zamiast w evaluate?

A poza tym, to nie kupuję takich akcji że żeby zreprodukować buga na prawdę musisz mielić coś 30 minut, chyba że w na prawdę mega podziwnionych przypadkach, dla których ja znalazłbym inne określenie (wink, wink, bad architecture). Bo jeśli ktoś szuka błędów z concurrency przy użyciu debuggera to moim zdaniem już na starcie jesteś spalony.

Nie mówię że coś zaprezentowane przez autora jest głupie - bo to jest fajna zabawka. Ale nie widzę co takiego można przy jej użyciu zrobić czego nie można z istniejącymi już narzędziami.

1

Nie istnieje już coś takiego? https://github.com/breuleux/jurigged
I zgadzam się z @TomRiddle - fajna zabawka, ale nigdy nie słyszałem zbytniego zapotrzebowania na coś takiego w Pythonie.

1

@TomRiddle:

A nawet jeśli już miałbyś już znaleźć takiego buga, to czemu miałbyś nie użyć wtedy "watch" z debuggera albo "evaluate expression"?

Ale przecież to zrobisz raz, a kod zmieniony już będzie się cały czas wykonywał

Weź na warsztat np. pętlę - i watchem oraz eval expr. zmienisz jedną iterację, a zmieniając kod w locie zmienisz jej działanie na stałe.

1
1a2b3c4d5e napisał(a):

Ale przecież to zrobisz raz, a kod zmieniony już będzie się cały czas wykonywał

Weź na warsztat np. pętlę - i watchem oraz eval expr. zmienisz jedną iterację, a zmieniając kod w locie zmienisz jej działanie na stałe.

Mógłbyś wziąć pętlę do evaluate'a

0

@TomRiddle:

dafq? weź to pokaż

ja w vs w eval expr. zazwyczaj proste rzeczy evaluatowałem, nie wiem czemu miałbym tam pętle np. forka wrzucić

0
1a2b3c4d5e napisał(a):

@TomRiddle:

dafq? weź to pokaż

ja w vs w eval expr. zazwyczaj proste rzeczy evaluatowałem, nie wiem czemu miałbym tam pętle wrzucić

vs.

1a2b3c4d5e napisał(a):

Weź na warsztat np. pętlę - i watchem oraz eval expr. zmienisz jedną iterację, a zmieniając kod w locie zmienisz jej działanie na stałe.

1

masz kod:

for (int i=0; i<asd.Length; i++)
{
  DoStuff();
}

stawiasz break pointa

for (int i=0; i<asd.Length; i++)
{ <-------- BP
  DoStuff();
}

zmieniasz body

for (int i=0; i<asd.Length; i++)
{ 
  DoStuffDifferently();
}

proszę, o to Edit&Continue, jakbyś to chciał uzyskać (w miare sensownie) przy eval expr? nie twierdzę że się nie da, ale po co?

4

@TomRiddle: Przy wiekszych projektach czas startupu jest wysoki i restartowanie calego procesu jest po prostu czasochlonne (20s run, 50s debug aplikacja django z poprzedniej pracy).
Przy takim startupie koszt naprawy malego bledu (literowka np) jest duzy.

Inny scenariusz to zreprodukowanie bledu albo wprowadzenie interpretera w dana funkcje moze trwac minuty albo i wiecej.

Oczywiscie mozesz kombinowac z evaluate, ale jak to wczesniej inny ludzie opisali nie bedzie to dzialac w wiekszosci przypadkow. No i tez to jest na okolo bo musisz i tak pozniej do kodu przekleic wiec podwojna robota plus mozliwosc pomylki. Dodatkowa nie da sie debugowac kodu w oknie evaluate.

Tak samo jak nie musisz korzystac z narzedzia zwanego debuggerem tylko printy wrzucac w kod tak samo mozesz kombinowac na okolo. Mozna ale po co ;)

@randomize111: Ta biblioteka wspiera tylko podstawowe przypadki plus nie da sie modyfikowac w trakcie debugowania i z tego co widze autor juz nad nia nie pracuje.

1

Na tym forum nie idzie dogodzić ludziom :)

0

@TomRiddle: Zgaduję, że takoe flow z reloadem może być całkiem produktywne, jak ktoś dużo eksperymentuje i np. co chwile rozkłada na czynniki pierwsze zewnętrzne liby. Wada jaką widzę to konieczność nauki takiego podejścia, żeby wszystko działało efektywnie

0

@Kwazar90: Brakuje dokumentacji w formie diagramu / opisu wygenerowanej w standardzie Sphinx
GitHub ma wbudowane Action które może utworzyć taką dokumentacje w kontenerze i wrzucić artefakt na serwer następnie wyświetlić jako GitHub pages

Chyba że kierujesz się moim przesłaniem:
Nie ma dokumentacji, wiedza jest w ludziach

0

@Kwazar90: Ej - świetne to jest !

0

@Kwazar90 Fajne, szkoda że py2.7 nie jest wspierany :(

2

Prawdopodobnie nawet by się nie dało na python 2.7 tego zaimplementować, ciężko było na python 3.6 też.
Dodatkowo bez type hintingu kod byłby całkowicie nieczytelny.

1

A zapomniałem - gratki głównej HNa

1 użytkowników online, w tym zalogowanych: 0, gości: 1