"""Python Cookbook

Chapter 2, Examples from the text.

Note: Output from this is used in Chapter 4 examples.

•	Writing python script and module files
•	Writing long lines of code
•	Including descriptions and documentation
•	Better RST markup in docstrings
•	Designing complex if...elif chains
•	Saving intermediate results with the := “walrus”
•	Avoiding a potential problem with break statements
•	Leveraging the exception matching rules
•	Avoiding a potential problem with an except: clause
•	Concealing exception root cause
•	Managing a context using the with statement

Since these are almost all examples of the REPL, it's easier to
show this is a long interaction.

"""


# Recipe 1
# Writing python script and module files
>>> print("hello world")
hello world

# Recipe 2
# Writing long lines of code
>>> import math
>>> example_value = (63/25) * (17+15*math.sqrt(5)) / (7+15*math.sqrt(5))
>>> mantissa_fraction, exponent = math.frexp(example_value)
>>> mantissa_whole = int(mantissa_fraction*2**53)
>>> message_text = f'the internal representation is {mantissa_whole:d}/2**53*2**{exponent:d}'
>>> print(message_text)
the internal representation is 7074237752514592/2**53*2**2

>>> import math
>>> example_value = (63/25) * (17+15*math.sqrt(5)) / (7+15*math.sqrt(5))
>>> mantissa_fraction, exponent = math.frexp(example_value)
>>> mantissa_whole = int(mantissa_fraction*2**53)

>>> message_text = f'the internal representation is {mantissa_whole:d}/2**53*2**{exponent:d}'
>>> message_text = f'the internal representation is \
... {mantissa_whole:d}/2**53*2**{exponent:d}'

>>> message_text
'the internal representation is 7074237752514592/2**53*2**2'

>>> import math
>>> example_value1 = (63/25) * (17+15*math.sqrt(5)) / (7+15*math.sqrt(5))
>>> example_value2 = (63/25) * ( (17+15*math.sqrt(5)) / (7+15*math.sqrt(5)) )
>>> example_value2 == example_value1
True

>>> example_value3 = (63/25) * (
...      (17+15*math.sqrt(5))
...    / ( 7+15*math.sqrt(5))
... )
>>> example_value3 == example_value1
True

>>> message_text = (
... f'the internal representation '
... f'is {mantissa_whole:d}/2**53*2**{exponent:d}'
... )
>>> message_text
'the internal representation is 7074237752514592/2**53*2**2'

>>> import math
>>> example_value = (63/25) * (17+15*math.sqrt(5)) / (7+15*math.sqrt(5))

>>> a = (63/25)
>>> b = (17+15*math.sqrt(5))
>>> c = (7+15*math.sqrt(5))
>>> example_value = a * b / c

>>> print(
...    'several values including',
...    'mantissa =', mantissa_fraction,
...    'exponent =', exponent
... )
several values including mantissa = 0.785398163451422 exponent = 2

>>> from math import (sin, cos, tan,
...    sqrt, log, frexp)


# Recipe 6
# Saving intermediate results with the := “walrus"

>>> s = sum((1/(2*n+1))**2 for n in range(0, 20_000))
>>> round(math.sqrt(8*s), 4)
3.1416

>>> b = 0
>>> for n in range(0, 20_000):
...     if (1/(2*n+1))**2 >= 0.000_000_001:
...         b = b + (1/(2*n+1))**2
>>> round(math.sqrt(8*b), 4)
3.1416

>>> p = 0
>>> for n in range(0, 20_000):
...     term = (1/(2*n+1))**2
...     if term >= 0.000_000_001:
...         p = p + term
>>> round(math.sqrt(8*p), 4)
3.1416

>>> q = 0
>>> for n in range(0, 20_000):
...     if (term := (1/(2*n+1))**2) >= 0.000_000_001:
...         q = q + term
...     else:
...         break
>>> round(math.sqrt(8*q), 4)
3.1416

>>> r = 0
>>> n = 0
>>> while (term := (1/(2*n+1))**2) >= 0.000_000_001:
...     r += term
...     n += 1
>>> round(math.sqrt(8*r), 4)
3.1416
>>> n
15811

>>> data = [11, 13, 17, 19, 23, 29]
>>> total = 0
>>> running_sum = [(total := total + d) for d in data]
>>> total
112
>>> running_sum
[11, 24, 41, 60, 83, 112]


# Recipe 7
# Avoiding a potential problem with break statements

>>> sample_1 = "some_name = the_value"
>>> for position in range(len(sample_1)):
...    if sample_1[position] in '=:':
...        break
>>> print(f"name={sample_1[:position]!r}",
...     f"value={sample_1[position+1:]!r}")
name='some_name ' value=' the_value'

>>> sample_2 = "name_only"
>>> for position in range(len(sample_2)):
...    if sample_2[position] in '=:':
...        break
>>> print(f"name={sample_2[:position]!r}",
...     f"value={sample_2[position+1:]!r}")
name='name_onl' value=''

>>> position = -1
>>> for position in range(len(sample_2)):
...    if sample_2[position] in '=:':
...        break
>>> if position == -1:
...     print(f"name=None value=None")
... elif not(sample_2[position] == ':' or sample_2[position] == '='):
...     print(f"name={sample_2!r} value=None")
... else:
...     print(f"name={sample_2[:position]!r}",
...         f"value={sample_2[position+1:]!r}")
name='name_only' value=None

>>> if len(sample_2) > 0:
...     name, value = sample_2, None
... else:
...     name, value = None, None
>>> for position in range(len(sample_2)):
...     if sample_2[position] in '=:':
...         name, value = sample_2[:position], sample2[position:]
...         break
>>> print(f"{name=} {value=}")
name='name_only' value=None


>>> for position in range(len(sample_2)):
...     if sample_2[position] in '=:':
...         name, value = sample_2[:position], sample_2[position+1:]
...         break
... else:
...     if len(sample_2) > 0:
...         name, value = sample_2, None
...     else:
...         name, value = None, None
>>> print(f"{name=} {value=}")
name='name_only' value=None

# Recipe 8
# Leveraging the exception matching rules

>>> from pathlib import Path
>>> import shutil
>>> source_dir = Path.cwd()/"data"
>>> target_dir = Path.cwd()/"backup"

>>> source_path = source_dir / "craps.csv"
>>> target_path = target_dir / "craps.csv"
>>> try:
...     target = shutil.copy(source_path, target_path)
... except FileNotFoundError:
...     target_path.parent.mkdir(exist_ok=True, parents=True)
...     target = shutil.copy(source_path, target_path)
... except OSError as ex:
...     print(f"Copy {source_path} to {target_path} error {ex}")


# Recipe 10
# Concealing exception root cause
>>> class MyAppError(Exception):
...     pass

>>> try:
...     None.some_method(42)
... except AttributeError as exception:
...     raise MyAppError("Some Known Problem")  # doctest: +ELLIPSIS
Traceback (most recent call last):
...
MyAppError: Some Known Problem

Actual: show's root cause.
Traceback (most recent call last):
  File "<doctest examples.txt[66]>", line 2, in <module>
    None.some_method(42)
AttributeError: 'NoneType' object has no attribute 'some_method'
<BLANKLINE>
During handling of the above exception, another exception occurred:
<BLANKLINE>
Traceback (most recent call last):
  File "/Applications/PyCharm CE.app/Contents/helpers/pycharm/docrunner.py", line 139, in __run
    exec(compile(example.source, filename, "single",
  File "<doctest examples.txt[66]>", line 4, in <module>
    raise MyAppError("Some Known Problem")  # doctest: +IGNORE_EXCEPTION_DETAIL,+NORMALIZE_WHITESPACE
MyAppError: Some Known Problem


>>> try:
...     None.some_method(42)
... except AttributeError as exception:
...     raise MyAppError("Some Known Problem") from None
Traceback (most recent call last):
  File "/Applications/PyCharm CE.app/Contents/helpers/pycharm/docrunner.py", line 139, in __run
    exec(compile(example.source, filename, "single",
  File "<doctest examples.txt[67]>", line 4, in <module>
    raise MyAppError("Some Known Problem") from None
MyAppError: Some Known Problem

>>> try:
...     None.some_method(42)
... except AttributeError as exception:
...     try:
...         raise MyAppError("details")
...     except MyAppError as ex:
...         print(ex.__context__)
...         print(ex.__cause__)
'NoneType' object has no attribute 'some_method'
None


# Recipe 11
# Managing a context using the with statement

>>> import csv
>>> from pathlib import Path
>>> some_source = [[2,3,5], [7,11,13], [17,19,23]]

>>> target_path = Path.cwd()/"data"/"ex2_r12.csv"
>>> with target_path.open('w', newline='') as target_file:
...     writer = csv.writer(target_file)
...     writer.writerow(['column', 'data', 'heading'])
...     writer.writerows(some_source)
21
>>> print(f'finished writing {target_path.name}')
finished writing ex2_r12.csv

>>> source_path = Path.cwd()/"data"/"ex2_r12.csv"
>>> with source_path.open() as source_file:
...     reader = csv.reader(source_file)
...     data = list(reader)
>>> data
[['column', 'data', 'heading'], ['2', '3', '5'], ['7', '11', '13'], ['17', '19', '23']]

>>> target_path = Path.cwd()/"data"/"ex2_r12.csv"
>>> target_path.unlink()  # Be sure it's gone.

>>> try:
...     with target_path.open('w', newline='') as target_file:
...         writer = csv.writer(target_file)
...         wrote = writer.writerow(['column', 'data', 'heading'])
...         wrote = writer.writerow(some_source[0])
...         raise Exception("Testing")
... except Exception as exc:
...     print(f"{target_file.closed=}")
...     print(f"{exc=}")
target_file.closed=True
exc=Exception('Testing')
>>> print(f"Finished Writing {target_path.name}")
Finished Writing ex2_r12.csv

Note: Output from this is used in Chapter 4 examples.
