#%% K čemu vlastně je context manager?
with open('./p03_advanced_features/01_collections.py', 'r') as f:
    print(f'inside with: f.closed? {f.closed}')
    collections_src = f.read()

print(f'after with: f.closed? {f.closed}')


#%% Zpracování výjimek:
try:
    with open('./p03_advanced_features/01_collections.py', 'r') as f:
        raise ValueError()
except:
    print(f'Exception raised!')
    pass

print(f'after with: f.closed? {f.closed}')


#%% Definice vlastního context manageru:
class MyContextManager:
    def __init__(self):
        print('Init method called!')

    def __enter__(self):
        print('Entering the context.')
        return 42

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f'Exitting! exc_type = {repr(exc_type)}, exc_val = {repr(exc_val)}, exc_tb = {repr(exc_tb)}')


with MyContextManager() as value:
    print(f'inside with: value = {value}')


#%% Není nutno vytvářet přímo ve with:
context_manager = MyContextManager()
print('... some work ...')
with context_manager as value:
    print(f'inside with: value = {value}')


#%% Pokud dojde k výjimce:
with MyContextManager():
    raise ValueError("We don't like the value!")


#%% Potlačení výjimky:
class SupressExceptionManager:
    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        return True


with SupressExceptionManager():
    raise ValueError('Nobody can hear me scream...')


#%% TODO: Napište context manager, který změří dobu vykonávání kusu kódu.

pass


#%% contextlib.closing():
from contextlib import closing
from urllib.request import urlopen
from http.client import HTTPResponse


response: HTTPResponse = urlopen('https://lynt.cz/')
with closing(response):
    print(response.read(1024))


#%% contextlib.supress():
from contextlib import suppress


total_price = 1024
quantity = 0
unit_price = 0

with suppress(ZeroDivisionError, ValueError):
    unit_price = total_price / quantity
    raise ValueError()

print(f'unit_price = {unit_price}')

# Lze použít obecné Exception pro zachycení všech výjimek:
with suppress(Exception):
    unit_price = total_price / quantity
    raise ValueError()


#%% contextlib.redirect_stdout():
from contextlib import redirect_stdout
from io import StringIO


buffer = StringIO()
with redirect_stdout(buffer):
    help(redirect_stdout)

print(f'buffer = {buffer.getvalue()}')


#%% Novinka v Python 3.7: contextlib.nullcontext():
from contextlib import nullcontext
from io import StringIO

redirect_to_buffer = StringIO()
if redirect_to_buffer is not None:
    context = redirect_stdout(redirect_to_buffer)
else:
    context = nullcontext()

with context:
    help(nullcontext)

if redirect_to_buffer is not None:
    print('Buffer was enabled, it contains:')
    print(buffer.getvalue())


#%% TODO: Napište vlastní nullcontext pro starší verze Pythonu.

pass
