Add docstrings for everything
- ID
933311f- date
2024-08-24 09:24:47+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
1ce232c- message
Add docstrings for everything- changed files
2 files, 126 additions, 4 deletions
Changed files
src/javascript/__init__.py (4687) → src/javascript/__init__.py (5019)
diff --git a/src/javascript/__init__.py b/src/javascript/__init__.py
index 2e64194..36ec47f 100644
--- a/src/javascript/__init__.py
+++ b/src/javascript/__init__.py
@@ -1,3 +1,16 @@
+"""
+This is a collection of Python functions for manipulating JavaScript
+"data files" -- that is, JavaScript files that define a single variable
+with a JSON value.
+
+This is an example of a JavaScript data file:
+
+ const shape = { "sides": 5, "colour": "red" };
+
+Think of this like the JSON module, but for JavaScript files.
+
+"""
+
import json
import pathlib
import re
tests/test_javascript.py (7664) → tests/test_javascript.py (10705)
diff --git a/tests/test_javascript.py b/tests/test_javascript.py
index d33c509..afad739 100644
--- a/tests/test_javascript.py
+++ b/tests/test_javascript.py
@@ -1,3 +1,7 @@
+"""
+Tests for the ``javascript`` module.
+"""
+
import pathlib
import typing
@@ -8,10 +12,19 @@ from javascript import append_to_js_array, append_to_js_object, read_js, write_j
@pytest.fixture
def js_path(tmp_path: pathlib.Path) -> pathlib.Path:
+ """
+ Returns a path to a JavaScript file.
+
+ This only returns the path and does not create the file.
+ """
return tmp_path / "data.js"
class TestReadJs:
+ """
+ Tests for the ``read_js()`` function.
+ """
+
@pytest.mark.parametrize(
"text",
[
@@ -23,21 +36,49 @@ class TestReadJs:
],
)
def test_can_read_file(self, js_path: pathlib.Path, text: str) -> None:
+ """
+ JavaScript "data values" can be read from files, with a certain
+ amount of allowance for:
+
+ * whitespace
+ * trailing semicolon or not
+ * a var/const prefix
+
+ """
js_path.write_text(text)
assert read_js(js_path, varname="redPentagon") == {"sides": 5, "colour": "red"}
- def test_non_existent_file_is_error(self) -> None:
+ def test_error_if_path_does_not_exist(self) -> None:
+ """
+ Reading a file which doesn't exist throws a FileNotFoundError.
+ """
with pytest.raises(FileNotFoundError):
read_js("doesnotexist.js", varname="shape")
+ def test_error_if_path_is_directory(self, tmp_path: pathlib.Path) -> None:
+ """
+ Reading a path which is a directory throws an IsADirectoryError.
+ """
+ assert tmp_path.is_dir()
+
+ with pytest.raises(IsADirectoryError):
+ read_js(tmp_path, varname="shape")
+
def test_non_json_value_is_error(self, js_path: pathlib.Path) -> None:
+ """
+ Reading a file which doesn't contain a JavaScript "data value"
+ throws a ValueError.
+ """
js_path.write_text("const sum = 1 + 1 + 1;")
with pytest.raises(ValueError):
read_js(js_path, varname="sum")
def test_incorrect_varname_is_error(self, js_path: pathlib.Path) -> None:
+ """
+ Reading a file with the wrong variable name throws a ValueError.
+ """
js_path.write_text(
'const redPentagon = {\n "sides": 5,\n "colour": "red"\n};\n'
)
@@ -49,7 +90,14 @@ class TestReadJs:
class TestWriteJs:
+ """
+ Tests for the ``write_js()`` function.
+ """
+
def test_can_write_file(self, js_path: pathlib.Path) -> None:
+ """
+ Writing to a file stores the correct JavaScript string.
+ """
red_pentagon = {"sides": 5, "colour": "red"}
write_js(js_path, value=red_pentagon, varname="redPentagon")
@@ -60,12 +108,18 @@ class TestWriteJs:
)
def test_fails_if_cannot_write_file(self) -> None:
+ """
+ Writing to the root folder throws an IsADirectoryError.
+ """
red_pentagon = {"sides": 5, "colour": "red"}
with pytest.raises(IsADirectoryError):
write_js("/", value=red_pentagon, varname="redPentagon")
def test_fails_if_target_is_folder(self, tmp_path: pathlib.Path) -> None:
+ """
+ Writing to a folder throws an IsADirectoryError.
+ """
assert tmp_path.is_dir()
red_pentagon = {"sides": 5, "colour": "red"}
@@ -74,6 +128,10 @@ class TestWriteJs:
write_js(tmp_path, value=red_pentagon, varname="redPentagon")
def test_creates_parent_directory(self, tmp_path: pathlib.Path) -> None:
+ """
+ If the parent directory of the output path doesn't exist, it is
+ created before the file is written.
+ """
js_path = tmp_path / "1/2/3/shape.js"
red_pentagon = {"sides": 5, "colour": "red"}
@@ -87,6 +145,10 @@ class TestWriteJs:
class TestAppendToArray:
+ """
+ Tests for the ``append_to_js_array`` function.
+ """
+
@pytest.mark.parametrize(
"text",
[
@@ -98,6 +160,13 @@ class TestAppendToArray:
],
)
def test_can_append_array_value(self, js_path: pathlib.Path, text: str) -> None:
+ """
+ After you append an item to an array, you can retrieve the
+ updated array.
+
+ This is true regardless of what the trailing whitespace in the
+ original file looks like.
+ """
js_path.write_text(text)
append_to_js_array(js_path, value="damson")
@@ -109,6 +178,9 @@ class TestAppendToArray:
]
def test_can_mix_types(self, js_path: pathlib.Path) -> None:
+ """
+ Arrays can contain a mixture of different types.
+ """
write_js(js_path, value=["apple", "banana", "coconut"], varname="fruit")
append_to_js_array(js_path, value=["damson"])
assert read_js(js_path, varname="fruit") == [
@@ -119,6 +191,10 @@ class TestAppendToArray:
]
def test_error_if_file_doesnt_look_like_array(self, js_path: pathlib.Path) -> None:
+ """
+ Appending to a file which doesn't contain a JSON array throws
+ a ValueError.
+ """
red_pentagon = {"sides": 5, "colour": "red"}
write_js(js_path, value=red_pentagon, varname="redPentagon")
@@ -142,6 +218,10 @@ class TestAppendToArray:
class TestAppendToObject:
+ """
+ Tests for the ``append_to_js_object`` function.
+ """
+
@pytest.mark.parametrize(
"text",
[
@@ -152,17 +232,30 @@ class TestAppendToObject:
'const redPentagon = {\n "colour": "red",\n "sides": 5\n}',
],
)
- def test_can_append_array_value(self, js_path: pathlib.Path, text: str) -> None:
+ def test_append_to_js_object(self, js_path: pathlib.Path, text: str) -> None:
+ """
+ After you add a key/value pair to an object, you can retrieve the
+ updated object.
+
+ This is true regardless of what the trailing whitespace in the
+ original file looks like.
+ """
js_path.write_text(text)
- append_to_js_object(js_path, key="sideLengths", value=[5, 5, 6, 6, 6])
+ assert read_js(js_path, varname="redPentagon") == {"colour": "red", "sides": 5}
+
+ append_to_js_object(js_path, key="sideLengths", value=[1, 2, 3, 4, 5])
assert read_js(js_path, varname="redPentagon") == {
"colour": "red",
"sides": 5,
- "sideLengths": [5, 5, 6, 6, 6],
+ "sideLengths": [1, 2, 3, 4, 5],
}
def test_error_if_file_doesnt_look_like_object(self, js_path: pathlib.Path) -> None:
+ """
+ Appending to a file which doesn't contain a JSON object throws
+ a ValueError.
+ """
shapes = ["apple", "banana", "cherry"]
write_js(js_path, value=shapes, varname="fruit")
@@ -186,6 +279,14 @@ class TestAppendToObject:
class TestRoundTrip:
+ """
+ A "round trip" is a test that we can use one function to store a value,
+ and another function to retrieve it.
+
+ It checks that the functions are consistent with each other, and aren't
+ losing any information along the way.
+ """
+
@pytest.mark.parametrize(
"value",
[
@@ -202,10 +303,18 @@ class TestRoundTrip:
def test_can_read_and_write_value(
self, js_path: pathlib.Path, value: typing.Any
) -> None:
+ """
+ After you write a value with ``write_js()``, you get the same value
+ back when you call ``read_js()``.
+ """
write_js(js_path, value=value, varname="myTestVariable")
assert read_js(js_path, varname="myTestVariable") == value
def test_can_append_to_file(self, js_path: pathlib.Path) -> None:
+ """
+ After you append a value to an array, you can read the entire file
+ and get the updated array.
+ """
write_js(js_path, value=["apple", "banana", "coconut"], varname="fruit")
append_to_js_array(js_path, value="damson")
assert read_js(js_path, varname="fruit") == [