r"""
Testuje szybkość jednej lub więcej wersji Pythona na zestawie prostych testów 
łańcuchów poleceń. Funkcja pozwala na zmianę badanych instrukcji. Mierzy czas wszystkich łańcuchów kodów w przekazanej liście za pomocą jednej z poniżej wymienionych opcji: 

1) Python uruchamiający ten skrypt za pomocą wywołań API;
2) zestaw Pythonów, których ścieżki są podane w formie listy, poprzez odczytywanie danych z wiersza poleceń (os.popen) z flagą -m, 
aby znaleźć odpowiedni plik w ścieżce wyszukiwania modułów. 

Tylko w trybie wiersza poleceń (2) zamienia wszystkie " w mierzonym kodzie na ', aby uniknąć konfliktów z argumentami umieszczonymi w cudzysłowie; dzieli instrukcje wielowierszowe na oddzielne, cytowane 
argumenty w wierszu, aby wszystkie mogły zostać uruchomione i zastępuje wszystkie tabulatory 
 wcięciem z 4 spacjami dla zachowania jednorodności. 

Ostrzeżenia: 
- Tryb wiersza poleceń może nie działać poprawnie, jeżeli testowane instrukcje zawierają 
podwójne cudzysłowy, cytowany ciąg instrukcji jest ogólnie niezgodny z powłoką lub wiersz poleceń 
przekracza limit długości polecenia dla powłoki danej platformy.
- PyPy jest obecnie w dużej mierze nieużyteczny w trybie wiersza poleceń (2), ponieważ jego zmodyfikowane wyjście modułu timeit w tym trybie jest nieodpowiednie w raporcie.
 - To (jeszcze?) nie wspiera instrukcji setup w żadnym trybie. Czas wszystkich instrukcji w testowanym bloku kodu jest wliczany do całkowitego czasu działania.

W przypadku niepowodzeń jako alternatywy użyj trybu wywołań API tego modułu, aby testować jedną wersję Pythona w danym momencie, lub domowego modułu timer.py.
"""

import sys, os, time, timeit
defnum, defrep= 1000, 5    # Może się różnić w zależności od badanej instrukcji

def show_context(): 
    """
    Pokaż kontekst uruchomienia, używając, być może zbyt entuzjastycznego, f-stringa, 
    który nie działa na PyPy 3.10 bez użycia "..." dla zagnieżdżonych ' cudzysłowów.
    """
    print(f"Python {'.'.join(str(x) for x in sys.version_info[:3])}"
          f' na {sys.platform}'
          f" o {time.strftime('%b-%d-%Y, %H:%M:%S')}")

def runner(stmts, pythons=None, tracecmd=False):
    """
    Główna część programu: uruchamia test zgodnie z parametrami wejściowymi;
    wywołanie odpowiada za tryb działania.
    stmts:   [(number?, repeat?, stmt-string)]
    pythons: None=tylko bieżąca wersja lub  [python-executable-paths]
    """
    show_context()
    for (number, repeat, stmt) in stmts:
        number = number or defnum
        repeat = repeat or defrep    # 0=domyślnie

        if not pythons:
            # Uruchom stmt w tej wersji Pythona: wywołanie API 
            # Nie ma potrzeby dzielenia wierszy kodu ani cytowania
            best = min(timeit.repeat(stmt=stmt, number=number, repeat=repeat))
            print(f'{best:.4f}  {stmt[:70]!r}')

        else:
            # Uruchom stmt na wszystkich wersjach Pythona: wiersz poleceń
            # Dzielimy wiersze na szereg cytowanych argumentów
            print('-' * 80)
            print(repr(stmt))                                         # Pokaż cudzysłowy
            for python in pythons:
                stmt  = stmt.replace('"', "'")                        # Wszystkie " => '
                stmt  = stmt.replace('\t', ' ' * 4)                   # Tabulator => ____
                lines = stmt.split('\n')                              # Wiersz => arg
                args  = ' '.join(f'"{line}"' for line in lines)       # argument => "arg"

                oscmd = f'{python} -m timeit -n {number} -r {repeat} {args}'
                print(oscmd if tracecmd else python)
                print('\t' + os.popen(oscmd).read().rstrip())
