ch17: update from book draft

This commit is contained in:
Luciano Ramalho
2020-02-18 23:45:05 -03:00
parent 70650841b3
commit aa868e8f75
35 changed files with 788 additions and 31 deletions

View File

@@ -0,0 +1,7 @@
def tree(cls):
yield cls.__name__
if __name__ == '__main__':
for cls_name in tree(BaseException):
print(cls_name)

View File

@@ -0,0 +1,10 @@
def tree(cls):
yield cls.__name__, 0
for sub_cls in cls.__subclasses__():
yield sub_cls.__name__, 1
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,12 @@
def tree(cls):
yield cls.__name__, 0
for sub_cls in cls.__subclasses__():
yield sub_cls.__name__, 1
for sub_sub_cls in sub_cls.__subclasses__():
yield sub_sub_cls.__name__, 2
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,10 @@
def tree(cls, level=0):
yield cls.__name__, level
for sub_cls in cls.__subclasses__():
yield from tree(sub_cls, level + 1)
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,31 @@
from tree import tree
SPACES = ' ' * 4
HLINE = '\u2500' # ─ BOX DRAWINGS LIGHT HORIZONTAL
HLINE2 = HLINE * 2
ELBOW = f'\u2514{HLINE2} ' # └ BOX DRAWINGS LIGHT UP AND RIGHT
TEE = f'\u251C{HLINE2} ' # ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT
PIPE = f'\u2502 ' # │ BOX DRAWINGS LIGHT VERTICAL
def render_lines(tree_iter):
name, _, _ = next(tree_iter)
yield name
prefix = ''
for name, level, last in tree_iter:
if last:
connector = ELBOW
else:
connector = TEE
prefix = prefix[:4 * (level-1)]
prefix = prefix.replace(TEE, PIPE).replace(ELBOW, SPACES)
prefix += connector
yield prefix + name
if __name__ == '__main__':
for line in render_lines(tree(BaseException)):
print(line)

View File

@@ -0,0 +1,105 @@
import pytest
from pretty_tree import tree, render_lines
def test_1_level():
result = list(render_lines(tree(BrokenPipeError)))
expected = [
'BrokenPipeError',
]
assert expected == result
def test_2_levels_1_leaf():
result = list(render_lines(tree(IndentationError)))
expected = [
'IndentationError',
'└── TabError',
]
assert expected == result
def test_3_levels_1_leaf():
class X: pass
class Y(X): pass
class Z(Y): pass
result = list(render_lines(tree(X)))
expected = [
'X',
'└── Y',
' └── Z',
]
assert expected == result
def test_4_levels_1_leaf():
class Level0: pass
class Level1(Level0): pass
class Level2(Level1): pass
class Level3(Level2): pass
result = list(render_lines(tree(Level0)))
expected = [
'Level0',
'└── Level1',
' └── Level2',
' └── Level3',
]
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
result = list(render_lines(tree(Branch)))
expected = [
'Branch',
'├── Leaf1',
'├── Leaf2',
'├── Leaf3',
'└── Leaf4',
]
assert expected == result
def test_3_levels_2_leaves():
class A: pass
class B(A): pass
class C(B): pass
class D(A): pass
class E(D): pass
result = list(render_lines(tree(A)))
expected = [
'A',
'├── B',
'│ └── C',
'└── D',
' └── E',
]
assert expected == result
def test_4_levels_4_leaves():
class A: pass
class B1(A): pass
class C1(B1): pass
class D1(C1): pass
class D2(C1): pass
class C2(B1): pass
class B2(A): pass
expected = [
'A',
'├── B1',
'│ ├── C1',
'│ │ ├── D1',
'│ │ └── D2',
'│ └── C2',
'└── B2',
]
result = list(render_lines(tree(A)))
assert expected == result

View File

@@ -0,0 +1,94 @@
from tree import tree
def test_1_level():
class One: pass
expected = [('One', 0, True)]
result = list(tree(One))
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
expected = [
('Branch', 0, True),
('Leaf1', 1, False),
('Leaf2', 1, False),
('Leaf3', 1, False),
('Leaf4', 1, True),
]
result = list(tree(Branch))
assert expected == result
def test_3_levels_1_leaf():
class X: pass
class Y(X): pass
class Z(Y): pass
expected = [
('X', 0, True),
('Y', 1, True),
('Z', 2, True),
]
result = list(tree(X))
assert expected == result
def test_4_levels_1_leaf():
class Level0: pass
class Level1(Level0): pass
class Level2(Level1): pass
class Level3(Level2): pass
expected = [
('Level0', 0, True),
('Level1', 1, True),
('Level2', 2, True),
('Level3', 3, True),
]
result = list(tree(Level0))
assert expected == result
def test_4_levels_3_leaves():
class A: pass
class B1(A): pass
class C1(B1): pass
class D1(C1): pass
class B2(A): pass
class D2(C1): pass
class C2(B2): pass
expected = [
('A', 0, True),
('B1', 1, False),
('C1', 2, True),
('D1', 3, False),
('D2', 3, True),
('B2', 1, True),
('C2', 2, True),
]
result = list(tree(A))
assert expected == result
def test_many_levels_1_leaf():
class Root: pass
level_count = 100
expected = [('Root', 0, True)]
parent = Root
for level in range(1, level_count):
name = f'Sub{level}'
cls = type(name, (parent,), {})
expected.append((name, level, True))
parent = cls
result = list(tree(Root))
assert len(result) == level_count
assert result[0] == ('Root', 0, True)
assert result[-1] == ('Sub99', 99, True)
assert expected == result

View File

@@ -0,0 +1,13 @@
def tree(cls, level=0, last_in_level=True):
yield cls.__name__, level, last_in_level
subclasses = cls.__subclasses__()
if subclasses:
last = subclasses[-1]
for sub_cls in subclasses:
yield from tree(sub_cls, level+1, sub_cls is last)
if __name__ == '__main__':
for cls_name, level, _ in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,8 @@
from tree import tree
def test_1_level():
class One: pass
expected = ['One']
result = list(tree(One))
assert expected == result

View File

@@ -0,0 +1,7 @@
def tree(cls):
yield cls.__name__
if __name__ == '__main__':
for cls_name in tree(BaseException):
print(cls_name)

View File

@@ -0,0 +1,25 @@
from tree import tree
def test_1_level():
class One: pass
expected = [('One', 0)]
result = list(tree(One))
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
expected = [
('Branch', 0),
('Leaf1', 1),
('Leaf2', 1),
('Leaf3', 1),
('Leaf4', 1),
]
result = list(tree(Branch))
assert expected == result

View File

@@ -0,0 +1,10 @@
def tree(cls):
yield cls.__name__, 0 # <1>
for sub_cls in cls.__subclasses__(): # <2>
yield sub_cls.__name__, 1 # <3>
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level # <4>
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,25 @@
from tree import tree
def test_1_level():
class One: pass
expected = [('One', 0)]
result = list(tree(One))
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
expected = [
('Branch', 0),
('Leaf1', 1),
('Leaf2', 1),
('Leaf3', 1),
('Leaf4', 1),
]
result = list(tree(Branch))
assert expected == result

View File

@@ -0,0 +1,14 @@
def tree(cls):
yield cls.__name__, 0
yield from sub_tree(cls) # <1>
def sub_tree(cls):
for sub_cls in cls.__subclasses__():
yield sub_cls.__name__, 1 # <2>
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,38 @@
from tree import tree
def test_1_level():
class One: pass
expected = [('One', 0)]
result = list(tree(One))
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
expected = [
('Branch', 0),
('Leaf1', 1),
('Leaf2', 1),
('Leaf3', 1),
('Leaf4', 1),
]
result = list(tree(Branch))
assert expected == result
def test_3_levels_1_leaf():
class X: pass
class Y(X): pass
class Z(Y): pass
expected = [
('X', 0),
('Y', 1),
('Z', 2),
]
result = list(tree(X))
assert expected == result

View File

@@ -0,0 +1,16 @@
def tree(cls):
yield cls.__name__, 0
yield from sub_tree(cls)
def sub_tree(cls):
for sub_cls in cls.__subclasses__():
yield sub_cls.__name__, 1
for sub_sub_cls in sub_cls.__subclasses__():
yield sub_sub_cls.__name__, 2
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,76 @@
from tree import tree
def test_1_level():
class One: pass
expected = [('One', 0)]
result = list(tree(One))
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
expected = [
('Branch', 0),
('Leaf1', 1),
('Leaf2', 1),
('Leaf3', 1),
('Leaf4', 1),
]
result = list(tree(Branch))
assert expected == result
def test_3_levels_1_leaf():
class X: pass
class Y(X): pass
class Z(Y): pass
expected = [
('X', 0),
('Y', 1),
('Z', 2),
]
result = list(tree(X))
assert expected == result
def test_4_levels_1_leaf():
class Level0: pass
class Level1(Level0): pass
class Level2(Level1): pass
class Level3(Level2): pass
expected = [
('Level0', 0),
('Level1', 1),
('Level2', 2),
('Level3', 3),
]
result = list(tree(Level0))
assert expected == result
def test_4_levels_3_leaves():
class A: pass
class B1(A): pass
class C1(B1): pass
class D1(C1): pass
class B2(A): pass
class D2(C1): pass
class C2(B2): pass
expected = [
('A', 0),
('B1', 1),
('C1', 2),
('D1', 3),
('D2', 3),
('B2', 1),
('C2', 2),
]
result = list(tree(A))
assert expected == result

View File

@@ -0,0 +1,20 @@
def tree(cls):
yield cls.__name__, 0
yield from sub_tree(cls)
# tag::SUB_TREE[]
def sub_tree(cls):
for sub_cls in cls.__subclasses__():
yield sub_cls.__name__, 1
for sub_sub_cls in sub_cls.__subclasses__():
yield sub_sub_cls.__name__, 2
for sub_sub_sub_cls in sub_sub_cls.__subclasses__():
yield sub_sub_sub_cls.__name__, 3
# end::SUB_TREE[]
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,94 @@
from tree import tree
def test_1_level():
class One: pass
expected = [('One', 0)]
result = list(tree(One))
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
expected = [
('Branch', 0),
('Leaf1', 1),
('Leaf2', 1),
('Leaf3', 1),
('Leaf4', 1),
]
result = list(tree(Branch))
assert expected == result
def test_3_levels_1_leaf():
class X: pass
class Y(X): pass
class Z(Y): pass
expected = [
('X', 0),
('Y', 1),
('Z', 2),
]
result = list(tree(X))
assert expected == result
def test_4_levels_1_leaf():
class Level0: pass
class Level1(Level0): pass
class Level2(Level1): pass
class Level3(Level2): pass
expected = [
('Level0', 0),
('Level1', 1),
('Level2', 2),
('Level3', 3),
]
result = list(tree(Level0))
assert expected == result
def test_4_levels_3_leaves():
class A: pass
class B1(A): pass
class C1(B1): pass
class D1(C1): pass
class B2(A): pass
class D2(C1): pass
class C2(B2): pass
expected = [
('A', 0),
('B1', 1),
('C1', 2),
('D1', 3),
('D2', 3),
('B2', 1),
('C2', 2),
]
result = list(tree(A))
assert expected == result
def test_many_levels_1_leaf():
class Root: pass
level_count = 100
expected = [('Root', 0)]
parent = Root
for level in range(1, level_count):
name = f'Sub{level}'
cls = type(name, (parent,), {})
expected.append((name, level))
parent = cls
result = list(tree(Root))
assert len(result) == level_count
assert result[0] == ('Root', 0)
assert result[-1] == ('Sub99', 99)
assert expected == result

View File

@@ -0,0 +1,15 @@
def tree(cls):
yield cls.__name__, 0
yield from sub_tree(cls, 1)
def sub_tree(cls, level):
for sub_cls in cls.__subclasses__():
yield sub_cls.__name__, level
yield from sub_tree(sub_cls, level+1)
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')

View File

@@ -0,0 +1,94 @@
from tree import tree
def test_1_level():
class One: pass
expected = [('One', 0)]
result = list(tree(One))
assert expected == result
def test_2_levels_4_leaves():
class Branch: pass
class Leaf1(Branch): pass
class Leaf2(Branch): pass
class Leaf3(Branch): pass
class Leaf4(Branch): pass
expected = [
('Branch', 0),
('Leaf1', 1),
('Leaf2', 1),
('Leaf3', 1),
('Leaf4', 1),
]
result = list(tree(Branch))
assert expected == result
def test_3_levels_1_leaf():
class X: pass
class Y(X): pass
class Z(Y): pass
expected = [
('X', 0),
('Y', 1),
('Z', 2),
]
result = list(tree(X))
assert expected == result
def test_4_levels_1_leaf():
class Level0: pass
class Level1(Level0): pass
class Level2(Level1): pass
class Level3(Level2): pass
expected = [
('Level0', 0),
('Level1', 1),
('Level2', 2),
('Level3', 3),
]
result = list(tree(Level0))
assert expected == result
def test_4_levels_3_leaves():
class A: pass
class B1(A): pass
class C1(B1): pass
class D1(C1): pass
class B2(A): pass
class D2(C1): pass
class C2(B2): pass
expected = [
('A', 0),
('B1', 1),
('C1', 2),
('D1', 3),
('D2', 3),
('B2', 1),
('C2', 2),
]
result = list(tree(A))
assert expected == result
def test_many_levels_1_leaf():
class Root: pass
level_count = 100
expected = [('Root', 0)]
parent = Root
for level in range(1, level_count):
name = f'Sub{level}'
cls = type(name, (parent,), {})
expected.append((name, level))
parent = cls
result = list(tree(Root))
assert len(result) == level_count
assert result[0] == ('Root', 0)
assert result[-1] == ('Sub99', 99)
assert expected == result

View File

@@ -0,0 +1,10 @@
def tree(cls, level=0):
yield cls.__name__, level
for sub_cls in cls.__subclasses__():
yield from tree(sub_cls, level+1)
if __name__ == '__main__':
for cls_name, level in tree(BaseException):
indent = ' ' * 4 * level
print(f'{indent}{cls_name}')