sync with Atlas

This commit is contained in:
Luciano Ramalho
2021-07-10 11:58:24 -03:00
parent a77e6d1e97
commit 1283115921
8 changed files with 108 additions and 70 deletions

View File

@@ -23,8 +23,8 @@ metro_areas = [
def main(): def main():
print(f'{"":15} | {"latitude":>9} | {"longitude":>9}') print(f'{"":15} | {"latitude":>9} | {"longitude":>9}')
for record in metro_areas: for record in metro_areas:
match record: match record: # <1>
case [name, _, _, (lat, lon)] if lon <= 0: case [name, _, _, (lat, lon)] if lon <= 0: # <2>
print(f'{name:15} | {lat:9.4f} | {lon:9.4f}') print(f'{name:15} | {lat:9.4f} | {lon:9.4f}')
# end::MAIN[] # end::MAIN[]

View File

@@ -0,0 +1,72 @@
========================
Character Finder Utility
========================
Usage tips
==========
`cf.py` works as an executable on Unix-like systems,
if you have `python3` on your `$PATH`::
$ chmod +x cf.py
$ ./cf.py cat eyes
U+1F638 😸 GRINNING CAT FACE WITH SMILING EYES
U+1F63B 😻 SMILING CAT FACE WITH HEART-SHAPED EYES
U+1F63D 😽 KISSING CAT FACE WITH CLOSED EYES
Use `wc -l` to count the number of hits::
$ ./cf.py hieroglyph | wc -l
1663
With `tee` you can get the output and the count::
$ ./cf.py trigram | tee >(wc -l)
U+2630 ☰ TRIGRAM FOR HEAVEN
U+2631 ☱ TRIGRAM FOR LAKE
U+2632 ☲ TRIGRAM FOR FIRE
U+2633 ☳ TRIGRAM FOR THUNDER
U+2634 ☴ TRIGRAM FOR WIND
U+2635 ☵ TRIGRAM FOR WATER
U+2636 ☶ TRIGRAM FOR MOUNTAIN
U+2637 ☷ TRIGRAM FOR EARTH
8
Running the tests
=================
Run the ``doctest`` module from the command line on
this README.rst file (using ``-v`` to make tests visible)::
$ python3 -m doctest README.rst -v
That's what the ``test.sh`` script does.
Tests
-----
Import functions for testing::
>>> from cf import find, main
Test ``find`` with single result::
>>> find('sign', 'registered') # doctest:+NORMALIZE_WHITESPACE
U+00AE ® REGISTERED SIGN
Test ``find`` with two results::
>>> find('chess', 'queen', last=0xFFFF) # doctest:+NORMALIZE_WHITESPACE
U+2655 ♕ WHITE CHESS QUEEN
U+265B ♛ BLACK CHESS QUEEN
Test ``find`` with no results::
>>> find('no_such_character')
Test ``main`` with no words::
>>> main([])
Please provide words to find.

View File

@@ -4,18 +4,13 @@ import unicodedata
FIRST, LAST = ord(' '), sys.maxunicode # <1> FIRST, LAST = ord(' '), sys.maxunicode # <1>
def find(*query_words, first=FIRST, last=LAST): # <2> def find(*query_words, first=FIRST, last=LAST): # <2>
query = {w.upper() for w in query_words} # <3> query = {w.upper() for w in query_words} # <3>
count = 0
for code in range(first, last + 1): for code in range(first, last + 1):
char = chr(code) # <4> char = chr(code) # <4>
name = unicodedata.name(char, None) # <5> name = unicodedata.name(char, None) # <5>
if name and query.issubset(name.split()): # <6> if name and query.issubset(name.split()): # <6>
print(f'U+{code:04X}\t{char}\t{name}') # <7> print(f'U+{code:04X}\t{char}\t{name}') # <7>
count += 1
print(f'({count} found)')
def main(words): def main(words):
if words: if words:
@@ -23,6 +18,5 @@ def main(words):
else: else:
print('Please provide words to find.') print('Please provide words to find.')
if __name__ == '__main__': if __name__ == '__main__':
main(sys.argv[1:]) main(sys.argv[1:])

View File

@@ -1,36 +0,0 @@
Doctests for ``cf.py``
======================
How to run the tests
----------------------
Run the ``doctest`` module from the command line::
$ python3 -m doctest cf_tests.rst
Tests
-----
Import functions for testing::
>>> from cf import find, main
Test ``find`` with single result::
>>> find("sign", "registered") # doctest:+NORMALIZE_WHITESPACE
U+00AE ® REGISTERED SIGN
(1 found)
Test ``find`` with two results::
>>> find("chess", "queen", last=0xFFFF) # doctest:+NORMALIZE_WHITESPACE
U+2655 ♕ WHITE CHESS QUEEN
U+265B ♛ BLACK CHESS QUEEN
(2 found)
Test ``main`` with no words::
>>> main([])
Please provide words to find.

View File

@@ -1,2 +1,2 @@
#!/bin/bash #!/bin/bash
python3 -m doctest cf_tests.rst $1 python3 -m doctest README.rst $1

View File

@@ -1,40 +1,48 @@
""" """
>>> clip('banana ', 6) >>> clip('banana split', 5)
'banana'
>>> clip('banana ', 7)
'banana'
>>> clip('banana ', 5)
'banana' 'banana'
>>> clip('banana split', 6) >>> clip('banana split', 6)
'banana' 'banana'
>>> clip('banana split', 7) >>> clip('banana split', 7)
'banana' 'banana'
>>> clip('banana split', 10) >>> clip('banana split', 8)
'banana' 'banana'
>>> clip('banana split', 11) >>> clip('banana split', 11)
'banana' 'banana'
>>> clip('banana split', 12) >>> clip('banana split', 12)
'banana split' 'banana split'
>>> clip('bananasplit', 5) >>> clip('banana-split', 3)
'bananasplit' 'banana-split'
>>> clip('banana split', 8)
'banana' Jess' tests:
>>> text = 'The quick brown fox jumps over the lazy dog.'
>>> clip14 = clip(text, max_len=14)
>>> clip14
'The quick'
>>> len(clip14)
9
>>> clip15 = clip(text, max_len=15)
>>> clip15
'The quick brown'
>>> len(clip15)
15
""" """
# tag::CLIP[] # tag::CLIP[]
def clip(text, max_len=80): def clip(text, max_len=80):
"""Return text clipped at the last space before or after max_len""" """Return max_len characters clipped at space if possible"""
text = text.rstrip() text = text.rstrip()
end = len(text) if len(text) <= max_len or ' ' not in text:
if end <= max_len:
return text return text
space_before = text.rfind(' ', 0, max_len) end = len(text)
if space_before >= 0: space_at = text.rfind(' ', 0, max_len + 1)
end = space_before if space_at >= 0:
end = space_at
else: else:
space_after = text.find(' ', max_len) space_at = text.find(' ', max_len)
if space_after >= 0: if space_at >= 0:
end = space_after end = space_at
return text[:end].rstrip() return text[:end].rstrip()
# end::CLIP[] # end::CLIP[]

View File

@@ -4,6 +4,6 @@
>>> clip.__code__ # doctest: +ELLIPSIS >>> clip.__code__ # doctest: +ELLIPSIS
<code object clip at 0x...> <code object clip at 0x...>
>>> clip.__code__.co_varnames >>> clip.__code__.co_varnames
('text', 'max_len', 'end', 'space_before', 'space_after') ('text', 'max_len', 'end', 'space_at')
>>> clip.__code__.co_argcount >>> clip.__code__.co_argcount
2 2

View File

@@ -1,11 +1,11 @@
# tag::BOOKDICT[] # tag::BOOKDICT[]
from typing import TypedDict, List from typing import TypedDict
import json import json
class BookDict(TypedDict): class BookDict(TypedDict):
isbn: str isbn: str
title: str title: str
authors: List[str] authors: list[str]
pagecount: int pagecount: int
# end::BOOKDICT[] # end::BOOKDICT[]
@@ -13,7 +13,7 @@ class BookDict(TypedDict):
AUTHOR_EL = '<AUTHOR>{}</AUTHOR>' AUTHOR_EL = '<AUTHOR>{}</AUTHOR>'
def to_xml(book: BookDict) -> str: # <1> def to_xml(book: BookDict) -> str: # <1>
elements: List[str] = [] # <2> elements: list[str] = [] # <2>
for key, value in book.items(): for key, value in book.items():
if isinstance(value, list): # <3> if isinstance(value, list): # <3>
elements.extend( elements.extend(
@@ -29,4 +29,4 @@ def to_xml(book: BookDict) -> str: # <1>
def from_json(data: str) -> BookDict: def from_json(data: str) -> BookDict:
whatever: BookDict = json.loads(data) # <1> whatever: BookDict = json.loads(data) # <1>
return whatever # <2> return whatever # <2>
# end::FROMJSON[] # end::FROMJSON[]