Skip to content

Commit

Permalink
Add text support to ReadWriteClient.write_message (#120)
Browse files Browse the repository at this point in the history
The Vestaboard Read / Write API now supports passing text in addition to
the previously-supported rows of character codes.

It also now returns HTTP 200 (instead of HTTP 201) upon a successful
write, so update the response logic accordingly.

I've noticed that this endpoint also now returns HTTP 405 when the
written message matches the board's existing message, returning a JSON
error like this:

    {
      'status': 'error',
      'message': 'Message fingerprint matches the message that is already displayed on the board'
    }

This is surfaced to the caller as an HTTPStatusError (just like any
other request failure), but I may look at ways to make this a little
friendlier if this is the official server-side behavior.
  • Loading branch information
jparise committed Jul 22, 2023
1 parent 1e076c1 commit 7143f0e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 9 deletions.
19 changes: 16 additions & 3 deletions tests/test_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,26 @@ def test_read_message_empty(
message = rw_client.read_message()
assert message is None

def test_write_message(self, rw_client: ReadWriteClient, respx_mock: MockRouter):
def test_write_message_text(
self, rw_client: ReadWriteClient, respx_mock: MockRouter
):
text = "abc"
respx_mock.post("https://rw.vestaboard.com/").respond(200)
rw_client.write_message(text)

def test_write_message_list(
self, rw_client: ReadWriteClient, respx_mock: MockRouter
):
chars = [[0] * COLS] * ROWS
respx_mock.post("https://rw.vestaboard.com/").respond(201)
respx_mock.post("https://rw.vestaboard.com/").respond(200)
assert rw_client.write_message(chars)
assert respx_mock.calls.called
assert respx_mock.calls.last.request.content == json.dumps(chars).encode()

def test_write_message_dimensions(self, rw_client: ReadWriteClient):
def test_write_message_list_dimensions(self, rw_client: ReadWriteClient):
with pytest.raises(ValueError, match=rf"expected a \({COLS}, {ROWS}\) array"):
rw_client.write_message([])

def test_write_message_type(self, rw_client: ReadWriteClient):
with pytest.raises(TypeError, match=r"unsupported message type"):
rw_client.write_message(True) # type: ignore
26 changes: 20 additions & 6 deletions vesta/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,29 @@ def read_message(self) -> Optional[Rows]:
return json.loads(layout)
return None

def write_message(self, message: Rows) -> bool:
def write_message(self, message: Union[str, Rows]) -> bool:
"""Write a message to the Vestaboard.
`message` must be a two-dimensional (6, 22) array of character codes
representing the exact positions of characters on the board.
`message` can be either a string of text or a two-dimensional (6, 22)
array of character codes representing the exact positions of characters
on the board.
If text is specified, the lines will be centered horizontally and
vertically. Character codes will be inferred for alphanumeric and
punctuation characters, or they can be explicitly specified using curly
braces containing the character code (such as ``{5}`` or ``{65}``).
:raises ValueError: if ``message`` is a list with unsupported dimensions
"""
validate_rows(message)
r = self.http.post("", json=message)
data: Union[Dict[str, str], Rows]
if isinstance(message, str):
data = {"text": message}
elif isinstance(message, list):
validate_rows(message)
data = message
else:
raise TypeError(f"unsupported message type: {type(message)}")

r = self.http.post("", json=data)
r.raise_for_status()
return r.status_code == httpx.codes.CREATED
return r.is_success

0 comments on commit 7143f0e

Please sign in to comment.