ch15: draft examples
This commit is contained in:
32
15-more-types/typeddict/books.py
Normal file
32
15-more-types/typeddict/books.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# tag::BOOKDICT[]
|
||||
from typing import TypedDict, List
|
||||
import json
|
||||
|
||||
class BookDict(TypedDict):
|
||||
isbn: str
|
||||
title: str
|
||||
authors: List[str]
|
||||
pagecount: int
|
||||
# end::BOOKDICT[]
|
||||
|
||||
# tag::TOXML[]
|
||||
AUTHOR_EL = '<AUTHOR>{}</AUTHOR>'
|
||||
|
||||
def to_xml(book: BookDict) -> str: # <1>
|
||||
elements: List[str] = [] # <2>
|
||||
for key, value in book.items():
|
||||
if isinstance(value, list): # <3>
|
||||
elements.extend(
|
||||
AUTHOR_EL.format(n) for n in value) # <4>
|
||||
else:
|
||||
tag = key.upper()
|
||||
elements.append(f'<{tag}>{value}</{tag}>')
|
||||
xml = '\n\t'.join(elements)
|
||||
return f'<BOOK>\n\t{xml}\n</BOOK>'
|
||||
# end::TOXML[]
|
||||
|
||||
# tag::FROMJSON[]
|
||||
def from_json(data: str) -> BookDict:
|
||||
whatever: BookDict = json.loads(data) # <1>
|
||||
return whatever # <2>
|
||||
# end::FROMJSON[]
|
||||
32
15-more-types/typeddict/books_any.py
Normal file
32
15-more-types/typeddict/books_any.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# tag::BOOKDICT[]
|
||||
from typing import TypedDict, List
|
||||
import json
|
||||
|
||||
class BookDict(TypedDict):
|
||||
isbn: str
|
||||
title: str
|
||||
authors: List[str]
|
||||
pagecount: int
|
||||
# end::BOOKDICT[]
|
||||
|
||||
# tag::TOXML[]
|
||||
AUTHOR_EL = '<AUTHOR>{}</AUTHOR>'
|
||||
|
||||
def to_xml(book: BookDict) -> str: # <1>
|
||||
elements: List[str] = [] # <2>
|
||||
for key, value in book.items():
|
||||
if isinstance(value, list): # <3>
|
||||
elements.extend(AUTHOR_EL.format(n)
|
||||
for n in value)
|
||||
else:
|
||||
tag = key.upper()
|
||||
elements.append(f'<{tag}>{value}</{tag}>')
|
||||
xml = '\n\t'.join(elements)
|
||||
return f'<BOOK>\n\t{xml}\n</BOOK>'
|
||||
# end::TOXML[]
|
||||
|
||||
# tag::FROMJSON[]
|
||||
def from_json(data: str) -> BookDict:
|
||||
whatever = json.loads(data) # <1>
|
||||
return whatever # <2>
|
||||
# end::FROMJSON[]
|
||||
20
15-more-types/typeddict/demo_books.py
Normal file
20
15-more-types/typeddict/demo_books.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from books import BookDict
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
def demo() -> None: # <1>
|
||||
book = BookDict( # <2>
|
||||
isbn='0134757599',
|
||||
title='Refactoring, 2e',
|
||||
authors=['Martin Fowler', 'Kent Beck'],
|
||||
pagecount=478
|
||||
)
|
||||
authors = book['authors'] # <3>
|
||||
if TYPE_CHECKING: # <4>
|
||||
reveal_type(authors) # <5>
|
||||
authors = 'Bob' # <6>
|
||||
book['weight'] = 4.2
|
||||
del book['title']
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
demo()
|
||||
23
15-more-types/typeddict/demo_not_book.py
Normal file
23
15-more-types/typeddict/demo_not_book.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from books import to_xml, from_json
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
def demo() -> None:
|
||||
NOT_BOOK_JSON = """
|
||||
{"title": "Andromeda Strain",
|
||||
"flavor": "pistachio",
|
||||
"authors": true}
|
||||
"""
|
||||
not_book = from_json(NOT_BOOK_JSON) # <1>
|
||||
if TYPE_CHECKING: # <2>
|
||||
reveal_type(not_book)
|
||||
reveal_type(not_book['authors'])
|
||||
|
||||
print(not_book) # <3>
|
||||
print(not_book['flavor']) # <4>
|
||||
|
||||
xml = to_xml(not_book) # <5>
|
||||
print(xml) # <6>
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
demo()
|
||||
112
15-more-types/typeddict/test_books.py
Normal file
112
15-more-types/typeddict/test_books.py
Normal file
@@ -0,0 +1,112 @@
|
||||
import json
|
||||
from typing import cast
|
||||
|
||||
from books import BookDict, to_xml, from_json
|
||||
|
||||
XML_SAMPLE = """
|
||||
<BOOK>
|
||||
\t<ISBN>0134757599</ISBN>
|
||||
\t<TITLE>Refactoring, 2e</TITLE>
|
||||
\t<AUTHOR>Martin Fowler</AUTHOR>
|
||||
\t<AUTHOR>Kent Beck</AUTHOR>
|
||||
\t<PAGECOUNT>478</PAGECOUNT>
|
||||
</BOOK>
|
||||
""".strip()
|
||||
|
||||
|
||||
# using plain dicts
|
||||
|
||||
def test_1() -> None:
|
||||
xml = to_xml({
|
||||
'isbn': '0134757599',
|
||||
'title': 'Refactoring, 2e',
|
||||
'authors': ['Martin Fowler', 'Kent Beck'],
|
||||
'pagecount': 478,
|
||||
})
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
def test_2() -> None:
|
||||
xml = to_xml(dict(
|
||||
isbn='0134757599',
|
||||
title='Refactoring, 2e',
|
||||
authors=['Martin Fowler', 'Kent Beck'],
|
||||
pagecount=478))
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
def test_5() -> None:
|
||||
book_data: BookDict = dict(
|
||||
isbn='0134757599',
|
||||
title='Refactoring, 2e',
|
||||
authors=['Martin Fowler', 'Kent Beck'],
|
||||
pagecount=478
|
||||
)
|
||||
xml = to_xml(book_data)
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
def test_6() -> None:
|
||||
book_data = dict(
|
||||
isbn='0134757599',
|
||||
title='Refactoring, 2e',
|
||||
authors=['Martin Fowler', 'Kent Beck'],
|
||||
pagecount=478
|
||||
)
|
||||
xml = to_xml(cast(BookDict, book_data)) # cast needed
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
def test_4() -> None:
|
||||
xml = to_xml(BookDict(
|
||||
isbn='0134757599',
|
||||
title='Refactoring, 2e',
|
||||
authors=['Martin Fowler', 'Kent Beck'],
|
||||
pagecount=478))
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
def test_7() -> None:
|
||||
book_data = BookDict(
|
||||
isbn='0134757599',
|
||||
title='Refactoring, 2e',
|
||||
authors=['Martin Fowler', 'Kent Beck'],
|
||||
pagecount=478
|
||||
)
|
||||
xml = to_xml(book_data)
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
def test_8() -> None:
|
||||
book_data: BookDict = {
|
||||
'isbn': '0134757599',
|
||||
'title': 'Refactoring, 2e',
|
||||
'authors': ['Martin Fowler', 'Kent Beck'],
|
||||
'pagecount': 478,
|
||||
}
|
||||
xml = to_xml(book_data)
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
BOOK_JSON = """
|
||||
{"isbn": "0134757599",
|
||||
"title": "Refactoring, 2e",
|
||||
"authors": ["Martin Fowler", "Kent Beck"],
|
||||
"pagecount": 478}
|
||||
"""
|
||||
|
||||
def test_load_book_0() -> None:
|
||||
book_data: BookDict = json.loads(BOOK_JSON) # typed var
|
||||
xml = to_xml(book_data)
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
def test_load_book() -> None:
|
||||
book_data = from_json(BOOK_JSON)
|
||||
xml = to_xml(book_data)
|
||||
assert xml == XML_SAMPLE
|
||||
|
||||
|
||||
NOT_BOOK_JSON = """
|
||||
{"isbn": 3.141592653589793
|
||||
"title": [1, 2, 3],
|
||||
"authors": ["Martin Fowler", "Kent Beck"],
|
||||
"flavor": "strawberry"}
|
||||
"""
|
||||
|
||||
def test_load_not_book() -> None:
|
||||
book_data: BookDict = json.loads(BOOK_JSON) # typed var
|
||||
xml = to_xml(book_data)
|
||||
assert xml == XML_SAMPLE
|
||||
20
15-more-types/typeddict/test_books_check_fails.py
Normal file
20
15-more-types/typeddict/test_books_check_fails.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from books import BookDict, to_xml
|
||||
|
||||
XML_SAMPLE = """
|
||||
<BOOK>
|
||||
\t<ISBN>0134757599</ISBN>
|
||||
\t<TITLE>Refactoring, 2e</TITLE>
|
||||
\t<AUTHOR>Martin Fowler</AUTHOR>
|
||||
\t<AUTHOR>Kent Beck</AUTHOR>
|
||||
\t<PAGECOUNT>478</PAGECOUNT>
|
||||
</BOOK>
|
||||
""".strip()
|
||||
|
||||
def test_3() -> None:
|
||||
xml = to_xml(BookDict(dict([ # Expected keyword arguments, {...}, or dict(...) in TypedDict constructor
|
||||
('isbn', '0134757599'),
|
||||
('title', 'Refactoring, 2e'),
|
||||
('authors', ['Martin Fowler', 'Kent Beck']),
|
||||
('pagecount', 478),
|
||||
])))
|
||||
assert xml == XML_SAMPLE
|
||||
Reference in New Issue
Block a user