Python and Viv · Files
Reading and writing text files
What to notice
write_text(path, s),read_text(path)andread_lines(path)are builtins that behave asPath.write_text,Path.read_textandread_text().splitlines(): UTF-8, newlines read as\n, andwrite_textgives back the number of characters written.- Viv has no
with open(...)and no file objects; a file is read or written whole. Reading a missing file stops the run with Python's words,No such file or directory: '...'. - In the browser there is no file system: the wasm runtime keeps a table of files, so a program can write a file and read it back in the browser.
print(text, end="")becomesprint(text.rstrip("\n")), since Viv'sprintalways ends the line.scores.index(max(scores))ismax([k for k to len(scores)], key=fn(k) -> scores[k]):list.indexexists in Viv for lists of strings, not for arrays of numbers. Both give the first position of the largest score.- The report is the same comprehension over
zip(names, scores)in both. - A string times a number repeats it in both:
"*" * (s // 10).
Python read_write.py · 33 lines
Viv read_write.viv · 36 lines
py2viv refuses read_write.py
1 imports
4from pathlib import Path
2# nothing to import: read_text, read_lines and write_text are builtins
py2viv refuses this program:
read_write.py:21:19: not numeric Python: unpacking a list of strings (lifted by R5)
name, score = line.split(",")
^^^^^^^^^^^^^^^
Only several returned values, a vector (its rows for a matrix are not unpacked) and a shape unpack.
read_write.py:22:18: not numeric Python: appending a value of unknown type to a list (lifted by R17)
names.append(name)
^^^^
A list py2viv grows holds numbers, or rows of numbers (a new list, a copy, or a tuple).
read_write.py:23:19: not numeric Python: appending a value of unknown type to a list (lifted by R17)
scores.append(float(score))
^^^^^^^^^^^^
A list py2viv grows holds numbers, or rows of numbers (a new list, a copy, or a tuple).
read_write.py:30:1: not numeric Python: print's end='' (lifted by R4)
print(Path("compare_report.txt").read_text(), end="")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Every Viv print ends its line: build the line in one print.
4 constructs outside the numeric subset (tools/py2viv/SUBSET.md) 2 write a file
7PATH = "compare_scores.csv"
8rows = ["name,score", "ann,72", "bob,95", "cy,88"]
9n = Path(PATH).write_text("\n".join(rows) + "\n")
10print("wrote", n, "characters")
5PATH = "compare_scores.csv"
6rows = ["name,score", "ann,72", "bob,95", "cy,88"]
7n = write_text(PATH, join("\n", rows) + "\n")
8print("wrote", n, "characters")
(refused)
3 read it back line by line
13with open(PATH) as f:
14 lines = f.read().splitlines()
15print(len(lines), "lines; header:", lines[0])
11lines = read_lines(PATH)
12print(len(lines), "lines; header:", lines[0])
(refused)
4 parse the rows
18names = []
19scores = []
20for line in lines[1:]:
21 name, score = line.split(",")
22 names.append(name)
23 scores.append(float(score))
24best = scores.index(max(scores))
25print(f"best: {names[best]} with {scores[best]:.0f}")
15names = []
16scores = []
17for line in lines[1:] {
18 name, score = line.split(",")
19 names = append(names, name)
20 scores = append(scores, float(score))
21}
22best = max([k for k to len(scores)], key=fn(k) -> scores[k])
23print(f"best: {names[best]} with {scores[best]:.0f}")
(refused)
5 write a report
28report = [f"{nm}: {'*' * int(s // 10)}" for nm, s in zip(names, scores)]
29Path("compare_report.txt").write_text("\n".join(report) + "\n")
30print(Path("compare_report.txt").read_text(), end="")
26report = [f"{nm}: {"*" * (s // 10)}" for nm, s in zip(names, scores)]
27write_text("compare_report.txt", join("\n", report) + "\n")
28print(read_text("compare_report.txt").rstrip("\n"))
(refused)
6 checks
33assert Path(PATH).read_text().count("\n") == len(rows)
31test "files" {
32 assert_true(read_text(PATH).count("\n") == len(rows))
33}
(refused)
What they print
identical — the two programs print the same text.
Dimmed lines are left out of the comparison. Each Viv test block prints one PASS line; the Python checks the same facts with assert, which prints nothing.
$ python3 read_write.py
wrote 31 characters4 lines; header: name,scorebest: bob with 95ann: *******bob: *********cy: ********
$ viv run read_write.viv
wrote 31 characters4 lines; header: name,scorebest: bob with 95ann: *******bob: *********cy: ********PASS files