Wybór wersji interpretera na podstawie wersji skryptu pythona

Wybór wersji interpretera na podstawie wersji skryptu pythona
EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0

Mam zainstalowane 2 wersje Pythona na swoim windowsie do którego prowadzą odpowiednie zmienne:

Kopiuj
> python --version
Python 3.7.1
> python2 --version
Python 2.7.15

Mam też listę projektów w nie wiadomo jakich wersjach (2 lub 3) a ich kodu nie mogę modyfikować (więc rozwiązania typu dodanie python_version() odpadają). To co potrzebuję zrobić to wiedzieć w jakiej wersji został napisany każdy z projektów.
Jest na to jakieś sensowne rozwiązanie?

edytowany 1x, ostatnio: eL
Althorion
Moderator C/C++
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 17 godzin
  • Postów:1603
0

Jak masz te projekty zrobione? Tzn. masz kod źródłowy (chociaż nie możesz go modyfikować) w ogóle, czy tylko pyc? Jeszcze co innego?

Jak masz kod, to możesz go przejrzeć w poszukiwaniu struktur, które są inne w różnych wersjach tego języka (np. łatwym do zauważenia jest print czy xrange).

EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0

Nie mogę w ogóle ich modyfikować. Szukanie struktur i patrzenie jak implementowany jest print wymaga ode mnie ręcznego przeglądania tych projektów a tego robić nie chcę. Chcę napisać coś takiego że podklejam link do katalogu z projektami i na wyjściu dostaję wersję każdego z nich bez ich modyfikacji.

Althorion
Moderator C/C++
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 17 godzin
  • Postów:1603
0

To takiej magii nie ma. Twórca kodu mógł wyrazić wprost, jakiej wersji Pythona używał (np. #!/usr/bin/env python3.7), ale nie musiał.

Najbliżej automatyzacji byłoby odpalanie z różnymi wersjami i patrzenie, która zadziała.

EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0

Sęk w tym że właśnie takiej magii potrzebuję ;) To założenie też mi nie pomaga bo nie mam pewności że ktoś to zdefiniował.
Póki co też jedyne co udało mi się uzyskać to odpalanie wszystkiego przez jeden i drugi interpreter i patrzenie co się wysypuje natomiast jest to dość czasochłonne rozwiązanie.
Udało mi się trafić jeszcze na to:
https://stackoverflow.com/questions/40886456/how-to-detect-if-code-is-python-3-compatible
Próbuję to zweryfikować ale jakoś tak działa mi jak chce i raz faktycznie w przypadku pythona 2 pokazał komunikat o błędzie ale teraz nie wiem dlaczego bez problemu w przypadku obu wersji kompiluje się bez żadnych problemów... Może ktoś ma jeszcze jakieś rozwiązanie?

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Napisz skrypt w pythonie który:

  • Otwiera pliki źrodłowe
  • Testuje kilka znanych różnic (jak print czy xrange)

;]


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:2 minuty
  • Postów:4886
0

Napisz sobie skrypt, który skanuje te pliki i szuka rzeczy typu: print <sth>, xrange, range, i markuje je zgodnie z wynikami.


edytowany 1x, ostatnio: lion137
EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0

Ok, to możę spróbuję jeszcze w te stronę pójść. @Shalom lub @lion137 jeśli przelecę sobie po tych plikach i znajdę np. coś takiego print 'Hello' to czy mogę wówczas uznać że cały projekt jest kompatybilny z Pythonem 2 i dalej nie ma sensu nic szukać? Pytanie może trochę głupie ale piszę w javie a to taki dodatkowy task z pythonem więc wolę się upewnić ;)

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

No nie wiadomo czy jest kompatybilny z pythonem 2 ale na pewno nie jest z pythonem 3 ;)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:2 minuty
  • Postów:4886
1

Zgadzam się z przedmówcą:), jeśli Znajdziesz co najmniej jedno print bez nawiasów albo xrange, to na pewno nie jest to trójka.


enedil
  • Rejestracja:ponad 11 lat
  • Ostatnio:około 12 godzin
  • Postów:1027
1

xrange nie koniecznie, bo np zdarza się, że projekty robią coś takiego:

Kopiuj
try:
    xrange
except NameError:
    xrange = range

Ogólne rekomendacje są takie, by użyć modułu AST, by skutecznie wykryć zmiany składniowe (print bez nawiasów, dozwolona mieszana intendacja wskazują na dwójkę). Innymi słowy, użyj pythona 3 do parsowania, jak dostaniesz błąd składniowy, to wiesz że raczej działa na Pythonie 2. W innych przypadkach zostaje heurystyka.

lion137
  • Rejestracja:około 8 lat
  • Ostatnio:2 minuty
  • Postów:4886
0

Jak widać, niestety, nie jest to takie proste.


EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0
enedil napisał(a):

Ogólne rekomendacje są takie, by użyć modułu AST, by skutecznie wykryć zmiany składniowe (print bez nawiasów, dozwolona mieszana intendacja wskazują na dwójkę). Innymi słowy, użyj pythona 3 do parsowania, jak dostaniesz błąd składniowy, to wiesz że raczej działa na Pythonie 2.

Dokładnie w te stronę póki co postanowiłem pójść.
Na początek ma taki skrypt:

Kopiuj
import ast


def code_compatible(code_data):
    try:
        ast.parse(code_data)
        return 'Python 3'
    except SyntaxError as exc:
        return 'Python 2'


filePath = 'somePath'
compatible = code_compatible(open(filePath).read())

print(compatible)

I okazuje się że radzi sobie dobrze. Nie piszę na codzień w Pythonie więc może są jakieś takie case'y o których nie wiem ale w przypadku range czy print radzi sobie wporządku.
Teraz żeby to miało sens wydaje mi się że trzeba by cały projekt prześledzić w poszukiwaniu plików *.py a następnie lecieć po kolei na kazdym takie wywołanie. Jeśli poleci Python 2 to wówczas można przerwać. Jeszcze tylko nie wymyśliłem jak to sensownie zrobić ale jest już jakiś punkt wyjścia ;)

edytowany 1x, ostatnio: eL
EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0

Mały update. W Pythonie tak jak już pisałem nie piszę na co dzień więc powiedzcie mi proszę czy takie rozwiązanie ma sens:

Kopiuj
import ast
import os


def file_compatibility(file_path):
    try:
        ast.parse(file_path)
        return 3
    except SyntaxError as exc:
        return 2


def project_compatibility(dir_path):
    for root, dirs, files in os.walk(dir_path):
        for file in files:
            if file.endswith(".py"):
                file_path = os.path.join(root, file)
                compatibility = file_compatibility(open(file_path).read())
                if compatibility == 2:
                    return 2
    return 3


dirPath = "../scripts"
print("Project compatible with Python " + str(project_compatibility(dirPath)))

Dodam tylko że generalnie działa, testowałem na printach i range i wyniki są takie jakie oczekuję... Są jakieś przypadki w których może się to wysypać albo w ogóle czy jest coś co może sprawić że nie ma to sensu?

edytowany 1x, ostatnio: eL
CorvusEtiam
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 4 lata
  • Postów:8
0
Kopiuj
import ast
import os


def file_compatibility(file_path):
    try:
        ast.parse(file_path)
        return 3
    except SyntaxError as exc:
        return 2


def project_compatibility(dir_path):
    for root, dirs, files in os.walk(dir_path):
        for file in files:
            if file.endswith(".py"):
                file_path = os.path.join(root, file)
                compatibility = file_compatibility(open(file_path).read())
                if compatibility == 2:
                    return 2
    return 3


dirPath = "../scripts"
print("Project compatible with Python " + str(project_compatibility(dirPath)))

Trochę nie widzę sensu, po co tutaj ta zmienna compatibility jest. Nie prościej od razu zwracać. Poza tym, uważaj na ten return 3, bo w ten sposób, dla wszystkich plików bez rozszerzenia *.py zwracasz, wartość 3. Poza tym jeszcze "ładniejszą" opcją, jest zastąpić tą końcówkę

Kopiuj
 def project_compatibility(dir_path):
    for root, dirs, files in os.walk(dir_path):
         for file in files:
             if file.endswith(".py"):
                 file_path = os.path.join(root, file)
                 yield (file_path, file_compatibility(open(file_path).read()))

Bo tak, to zwracasz tylko dla pierwszego napotkanego pliku.

edytowany 1x, ostatnio: CorvusEtiam
EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0
CorvusEtiam napisał(a):

Trochę nie widzę sensu, po co tutaj ta zmienna compatibility jest. Nie prościej od razu zwracać.

Właśnie wydaje mi się że nie. Trzeba przelecieć cały projekt wraz z podkatalogami sprawdzając wszystkie skrypty. Jeśli chociaż raz zwróci 2 to wówczas od razu można przerwać sprawdzanie i zwrócić 2. W przeciwnym wypadku trzeba szukać dalej.

CorvusEtiam napisał(a):

Poza tym, uważaj na ten return 3, bo w ten sposób, dla wszystkich plików bez rozszerzenia *.py zwracasz, wartość 3.

W sumie to chyba możemy przyjąć takie założenie. Chyba że są też inne elementy które nie są przechowywane w plikach *.py a mogą świadczyć o tym że skrypt jest kompatybilny tylko z Pythonem 2?

CorvusEtiam napisał(a):

Poza tym jeszcze "ładniejszą" opcją, jest zastąpić tą końcówkę

Kopiuj
... twoj kod

Bo tak, to zwracasz tylko dla pierwszego napotkanego pliku.

No tak tylko że właśnie tak nie powinno być że jeśli znajdę chociaż 1 plik kompatybilny z Python 2 to projekt jest w Python 2 a w innym przypadku muszę przelecieć wszystkie pliki wraz z podkatalogami?

edytowany 1x, ostatnio: eL
CorvusEtiam
  • Rejestracja:ponad 6 lat
  • Ostatnio:ponad 4 lata
  • Postów:8
0

Ok, jeśli twój projekt jest dobrze zorganizowany, tak że na każdy folder, cała jego zawartość to pliki pod python3 lub 2 to oczywiście. Jeśli masz po prostu zbiór mało powiązanych skryptów to moje rozwiązanie jest moim zdaniem bezpieczniejsze.

Wyciągnij log dla wszystkich katalogów i przejrzyj wybiórczo, czy się zgadzają. To jedyna opcja. Chyba, że masz gdzieś projekt mieszany 2<>3. To wtedy, wracasz do punktu wyjścia. Poza tym, z tym returnem na samym końcu pętli, jeśli folder nie zawiera plików *.py to dostaniesz błędną informację, ale skoro nie masz takiego problemu, to myślę, że poza tym jest ok.
Zastanów się nad zwracaniem tupli ( nazwa_sprawdzonego_pliku, wersja_pythona), łatwiej później dojść, które pliki były skanowane.
Albo po prostu wrzuć moduł logging i zapisz do loga, te informacje, w razie jakby co nie działało.

Kopiuj
* projekt1
* projekt2
     + projekt2a
     + projekt2b   

Gdzie, projekt2 i 2b mają różne wymagane wersje, też jest problemem, chyba, że u ciebie taka sytuacji nie występuje.

edytowany 1x, ostatnio: CorvusEtiam
EL
  • Rejestracja:około 13 lat
  • Ostatnio:3 miesiące
0
CorvusEtiam napisał(a):

Ok, jeśli twój projekt jest dobrze zorganizowany, tak że na każdy folder, cała jego zawartość to pliki pod python3 lub 2 to oczywiście. Jeśli masz po prostu zbiór mało powiązanych skryptów to moje rozwiązanie jest moim zdaniem bezpieczniejsze.

A to w ogóle możliwe?
Jeśli mamy projekt w którym wymieszane są skrypty z Python 2 i Python 3 to przecież do ich uruchomienia potrzebne są oba interpretety i trzeba wiedzieć dokładnie który jak urchamiać. Ktoś w ogóle tak pisze projekty? Przecież tego się pewnie utrzymać nie da.

Guaz
Bardziej tu chodzi o fakt, że możesz mieć np. studentów albo osoby które jeszcze nie piszą w dwójce. A potrzebuje 'prostego skryptu', więc omylnie nawrzuca/napisze kilka rzeczy w innej wersji. W dodatku warto byłoby też przechwycić wyjątek ImportError jeśli masz taką możliwość w AST. Od razu będzie wiadomo czego brakuje. Ogólnie to są bardzo rzadkie przypadki, ale staje się to użyteczne :).
CorvusEtiam
Dokładnie, zwłaszcza, jak pracujesz z danymi to większość kodu kończy w prostych 1 plikowych skryptach. Potem wystarczy dodać zarządzanie wersjami metodą "na studenta", czyli kopiuj/wklej i dostajesz takiego potworka.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)