From 3c125ac03573a7ae80090058d3601ca4dacd4366 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 11:57:22 -0600 Subject: [PATCH 01/10] test(warnings): * Correct tests that were falsely passing by generating their own warns --- tests/test_init.py | 57 ++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/tests/test_init.py b/tests/test_init.py index a1a9b66..9a9eb07 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -137,42 +137,35 @@ def test_below_pad(): def test_no_pad(): small_board = return_valid_too_small_board() vb = create_fake_vestaboard() - vb.raw(small_board) - # warnings.warn doesn't work with f strings - warning_message = 'you provided a list with length 6, which has been centered on the board by default. Either provide a list with length 6, or set the "pad" option to suppress this warning.' - # tests if specific warning type and message is raised - with pytest.warns(UserWarning, match=warning_message): - warnings.warn(warning_message, UserWarning) - expected = [ - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0], - [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - ] - assert small_board == expected + expected_warning = 'you provided a list with length 3, which has been centered vertically on the board by default. Either provide a list with length 6, or set the "pad" option to suppress this warning.' + with pytest.warns(UserWarning, match=expected_warning): + vb.raw(small_board) + expected = [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0], + [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + ] + assert small_board == expected def test_large_board(): large_board = return_valid_too_large_board() vb = create_fake_vestaboard() - vb.raw(large_board) - # warnings.warn doesn't work with f strings - warning_message = f'The Vestaboard API accepts only 6 lines of characters; you\'ve passed in {len(large_board)}. Only the first 6 will be shown.' - # tests if specific warning type and message is raised - with pytest.warns(UserWarning, match=warning_message): - warnings.warn(warning_message, UserWarning) - expected = [ - [0, 0, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0], - [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0], - [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0] - ] - for i in large_board: - print(i) - assert large_board == expected + expected_warning = f'The Vestaboard API accepts only 6 lines of characters; you\'ve passed in {len(large_board)}. Only the first 6 will be shown.' + + with pytest.warns(UserWarning, match=expected_warning): + vb.raw(large_board) + expected = [ + [0, 0, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0], + [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 5, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0], + [1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0] + ] + assert large_board == expected def create_fake_cred_file(): with open(os.path.dirname(os.path.dirname(__file__)) + '/credentials.txt', 'w') as f: From 68e492e0a0b65f7d33f43b576fdf53a7643c55bf Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 11:58:39 -0600 Subject: [PATCH 02/10] perf(errors): * Added a more helpful error when a user passes in something other than an instance of `Installable() as the first argument to `Board()` * Add doc string to `Board().raw()` method with argument types * Re-name parameter version of "installable" to lowercase --- vestaboard/__init__.py | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/vestaboard/__init__.py b/vestaboard/__init__.py index 12e0be9..d2dfa0e 100644 --- a/vestaboard/__init__.py +++ b/vestaboard/__init__.py @@ -12,17 +12,20 @@ import warnings class Board: - def __init__(self, Installable=False, apiKey=False, apiSecret=False, subscriptionId=False): + def __init__(self, installable=False, apiKey=False, apiSecret=False, subscriptionId=False): """ Returns an instance of Board(). Keyword arguments: - Installable - an instance of Installable() + installable - an instance of installable() apiKey - your Vestaboard API Key apiSecret - your Vestaboard API Secret - subscriptionId - your Subscription ID (this can be obtained for you by creating a new Installable() instance) + subscriptionId - your Subscription ID (this can be obtained for you by creating a new installable() instance) """ - if not Installable: #check for cred file + if installable and not isinstance(installable, Installable): + raise ValueError(f'Expected the first argument passed to be an instance of Installable, but instead got {type(installable)}. If you are not trying to pass an Installable, specify the name of the arguments, or pass "None" as the first argument.') + + if not installable: #check for cred file if (not apiKey or not apiSecret or not subscriptionId): try: creds = get_creds() @@ -31,17 +34,17 @@ def __init__(self, Installable=False, apiKey=False, apiSecret=False, subscriptio self.apiSecret = creds[1] self.subscriptionId = creds[2] elif (len(creds) < 3 or len(creds) > 3): - raise ValueError('Credentials have been saved, but one or more are missing. Create a new Installable and pass in saveCredentials=True, or pass in all three parameters when initializing a new Board.') + raise ValueError('Credentials have been saved, but one or more are missing. Create a new installable and pass in saveCredentials=True, or pass in all three parameters when initializing a new Board.') except FileNotFoundError: - raise ValueError('You must create an installable first or save credentials by passing saveCredentials=True into Installable().') + raise ValueError('You must create an installable first or save credentials by passing saveCredentials=True into installable().') else: self.apiKey = apiKey self.apiSecret = apiSecret self.subscriptionId = subscriptionId else: - self.apiKey = Installable.apiKey - self.apiSecret = Installable.apiSecret - self.subscriptionId = Installable.subscriptionId or subscriptionId + self.apiKey = installable.apiKey + self.apiSecret = installable.apiSecret + self.subscriptionId = installable.subscriptionId or subscriptionId def post(self, text): headers = { @@ -52,19 +55,26 @@ def post(self, text): requests.post(vbUrls.post.format(self.subscriptionId), headers=headers, json=finalText) def raw(self, charList: list, pad=None): + """ + Posts already-formatted characters to the board. + + Keyword arguments: + + `charList` - a list of character lists + + `pad` - adds padding when list or character lists is less than 6. Valid options are `top`, `bottom`, and `center`. + """ base_filler = [0] * 22 filler_needed = 6 - len(charList) for i, row in enumerate(charList): if not isinstance(row, list): raise ValueError(f'Nested items must be lists, not {type(row)}.') if len(row) != 22: - raise ValueError(f'Nested lists must be exactly 22 characters long. Element at {i} is {len(row)} characters long.') + raise ValueError(f'Nested lists must be exactly 22 characters long. Element at {i} is {len(row)} characters long. Use the Formatter().convertLine() function if you need to add padding to your row.') for j, char in enumerate(row): if not isinstance(char, int): raise ValueError(f'Nested lists must contain numbers only - check row {i} char {j} (0 indexed)') - if len(charList) == 6: - pass - elif len(charList) > 6: + if len(charList) > 6: # warnings.warn doesn't work with f strings warning_message = f'The Vestaboard API accepts only 6 lines of characters; you\'ve passed in {len(charList)}. Only the first 6 will be shown.' warnings.warn(warning_message) @@ -79,7 +89,7 @@ def raw(self, charList: list, pad=None): else: if pad == None: # warnings.warn doesn't work with f strings - warning_message = f'you provided a list with length {len(charList)}, which has been centered on the board by default. Either provide a list with length 6, or set the "pad" option to suppress this warning.' + warning_message = f'you provided a list with length {len(charList)}, which has been centered vertically on the board by default. Either provide a list with length 6, or set the "pad" option to suppress this warning.' warnings.warn(warning_message) while len(charList) < 6: charList.append(base_filler) From 367a07eeba735ceb7b826443f4e0da4283a30adc Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 11:59:46 -0600 Subject: [PATCH 03/10] docs: * Update repo needs * Add clarification on `.raw()` section * Add info under `.convert()` method --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b938cfd..47f6712 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ vboard.raw(characters) ![Board with raw input example](../media/rawexample.png?raw=true) ### New in Version 1.0.0 -The `.raw()` method now supports padding and truncating if more or fewer than 6 lines are provided! By default, your text will be centered vertically on the board, but will generate a warning (if an odd number of lines are provided, the additional line will be at the bottom). Supress this warning by passing in `pad='center'`. When passing in greater than 6 lines, the board will only display the first 6 lines. +The `.raw()` method now supports padding and truncating if more or fewer than 6 lines are provided! By default, your text will be centered vertically on the board, but will generate a warning (if an odd number of lines are provided, the additional line will be at the bottom). Supress this warning by passing in `pad='center'`. When passing in greater than 6 lines, the board will only display the first 6 lines, removing lines from the bottom. You can also specify whether you'd like the padding to be added above or below your text by passing in `pad='top'` or `pad='bottom'` (only available when passing in < 6 lines). `pad='top'` will add padding above your text (your text will be at the bottom of the board), and `pad='bottom'` will add padding below your text (your text will be at the top of the board). @@ -162,6 +162,7 @@ from vestaboard.formatter import Formatter Formatter().convert('Oh hi!') # Returns [15, 8, 0, 8, 9, 37] ``` +There is no limit to the number of letters you can convert. If you need to create a row with exactly 22 characters, you can use the `.convertLine()` method instead. To split by word, pass in the argument `byWord=True` along with your input string: @@ -192,8 +193,8 @@ Formatter().convertLine('Happy Birthday!') *** ## Repository Info and Disclaimers ### Needs -- Conversion from string to list of lists for `.raw()` method -- Unit and other tests inside the `/test` folder +- ~~Conversion from string to list of lists for `.raw()` method~~ ✅ Complete! +- ~~Unit and other tests inside the `/test` folder~~ ✅ Complete! - Suggestions or ideas for improvement are always welcome! Interested in contributing to this project? Send a PR with changes and I'd be happy to review! If you're having trouble with this library, be sure to [open an issue][] so that I can look into the problem. Any details that can be provided alongside the problem would be greatly appreciated. From 44efe73bfbcf04abea5529351cc72c8a73c6d9f5 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 12:00:12 -0600 Subject: [PATCH 04/10] chore(version): Bump version to v1.1.0 --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 9deaebc..d0e959f 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="Vestaboard", - version="0.5.0", + version="1.1.0", author="Shane Sutro", author_email="shane@shanesutro.com", description="A Vestaboard Wrapper", @@ -18,9 +18,11 @@ 'requests' ], classifiers=[ - "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", ], python_requires='>=3.6', ) \ No newline at end of file From 54be867425ed3248073b5e22092d90ec34948720 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 14:02:30 -0600 Subject: [PATCH 05/10] docs: Add changelog, update setuptools for build --- .travis.yml | 3 ++- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/.travis.yml b/.travis.yml index 3db2343..53c1407 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,8 @@ python: - '3.9' install: + - pip install -U setuptools - pip install -r requirements.txt - pip install . -script: pytest \ No newline at end of file +script: pytest diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..229de9d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,36 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [v1.0.1](https://github.com/SonicRift/Vestaboard/releases/tag/v1.0.1) - 2022-06-18 + +[Compare with v1.0.0](https://github.com/SonicRift/Vestaboard/compare/v1.0.0...v1.0.1) + + +## [v1.0.0](https://github.com/SonicRift/Vestaboard/releases/tag/v1.0.0) - 2022-01-07 + +[Compare with v0.5.0](https://github.com/SonicRift/Vestaboard/compare/v0.5.0...v1.0.0) + + +## [v0.5.0](https://github.com/SonicRift/Vestaboard/releases/tag/v0.5.0) - 2021-02-22 + +[Compare with v0.4.0](https://github.com/SonicRift/Vestaboard/compare/v0.4.0...v0.5.0) + + +## [v0.4.0](https://github.com/SonicRift/Vestaboard/releases/tag/v0.4.0) - 2021-02-12 + +[Compare with v0.3.1](https://github.com/SonicRift/Vestaboard/compare/v0.3.1...v0.4.0) + + +## [v0.3.1](https://github.com/SonicRift/Vestaboard/releases/tag/v0.3.1) - 2021-02-10 + +[Compare with v0.2.0-beta](https://github.com/SonicRift/Vestaboard/compare/v0.2.0-beta...v0.3.1) + + +## [v0.2.0-beta](https://github.com/SonicRift/Vestaboard/releases/tag/v0.2.0-beta) - 2021-02-09 + +[Compare with first commit](https://github.com/SonicRift/Vestaboard/compare/049afbf9bbb45f5e6b5b797023729471ab6e653f...v0.2.0-beta) + + From 565a407c401ca9ec57f8b45adfeb611ea2357917 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 14:18:09 -0600 Subject: [PATCH 06/10] chore: Bump requirements versions --- requirements.txt | 15 ++------------- tests/test_init.py | 1 - 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/requirements.txt b/requirements.txt index acb1544..b662c25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,2 @@ -attrs==20.3.0 -certifi==2020.12.5 -chardet==4.0.0 -idna==2.10 -iniconfig==1.1.1 -packaging==20.9 -pluggy==0.13.1 -py==1.10.0 -pyparsing==2.4.7 -pytest==6.2.2 -requests==2.25.1 -toml==0.10.2 -urllib3==1.26.5 +pytest==7.0.0 +requests==2.28.0 diff --git a/tests/test_init.py b/tests/test_init.py index 9a9eb07..9f6adc6 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -1,7 +1,6 @@ import vestaboard import pytest import os -import warnings validRawChar = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], From 581576600008cac41a2bc390118afbfdfac9a85e Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 14:23:57 -0600 Subject: [PATCH 07/10] chore: Re-downgrade requests --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b662c25..308b534 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ pytest==7.0.0 -requests==2.28.0 +requests==2.27.0 From 68bfc933e0d45b0ed2326ed50a469cb4b7cbd1f2 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 14:28:48 -0600 Subject: [PATCH 08/10] chore: Pin setuptools to 60.8.2 --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 308b534..5f47467 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pytest==7.0.0 requests==2.27.0 +setuptools==60.8.2 \ No newline at end of file From 48ddd4970eae0b8e955d3e6c8eb3f6b8b5eda906 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 14:41:33 -0600 Subject: [PATCH 09/10] chore: Remove setup tools from requirements --- .travis.yml | 3 +-- requirements.txt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 53c1407..32f3c58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,11 @@ language: python python: - - '3.6' - '3.7' - '3.8' - '3.9' install: - - pip install -U setuptools + - pip install setuptools==60.8.2 - pip install -r requirements.txt - pip install . diff --git a/requirements.txt b/requirements.txt index 5f47467..7facde0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ pytest==7.0.0 -requests==2.27.0 -setuptools==60.8.2 \ No newline at end of file +requests==2.27.0 \ No newline at end of file From 04bdf83ad461ec5de480fa47f18214eef39ddb86 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Sat, 18 Jun 2022 15:01:16 -0600 Subject: [PATCH 10/10] docs: Correct README.md formatting --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 47f6712..eb6ea8c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/SonicRift/Vestaboard) ![GitHub contributors](https://img.shields.io/github/contributors/SonicRift/Vestaboard) -This is a lightweight and unassuming wrapper for the Vestaboard API. This project is open source and no payment is necessary to use - project donations are always appreciated to help fund this effort. If interested, you can [ view the donation page here.](https://shanesutro.com/donate) +This is a lightweight and unassuming wrapper for the Vestaboard API. This project is open source and no payment is necessary to use - project donations are always appreciated to help fund this effort. If interested, you can [view the donation page here.](https://shanesutro.com/donate) By [Shane Sutro][] and [contributors](https://github.com/SonicRift/Vestaboard/graphs/contributors) @@ -37,15 +37,15 @@ Once created, you will need to store your API Key and API Secret - you'll need t - Via `pip`: ```pip3 install vestaboard``` -_Note: if using a virtual environment, use `pip` instead of `pip3`_ +*Note: if using a virtual environment, use `pip` instead of `pip3`* #### Usage This package will simplify the process of connecting your code to Vestaboard's API. By default, the module will store your API Key, API Secret, and Subscriber ID in a .txt file in the root folder of the project. -If you do _not_ want to store this, pass `saveCredentials=False` into the creation of an `Installable`. Alternatively, you may skip creating an `Installable` alltogether if you already know your Subscription ID (which you can get from Vestaboards official portal if you'd like to skip this step). +If you do *not* want to store this, pass `saveCredentials=False` into the creation of an `Installable`. Alternatively, you may skip creating an `Installable` alltogether if you already know your Subscription ID (which you can get from Vestaboards official portal if you'd like to skip this step). -If you do **_not_** know your Subscription ID call `Installable()` with your API Key and API Secret to find and store it: +If you do *not* know your Subscription ID call `Installable()` with your API Key and API Secret to find and store it: ```python import vestaboard #This will print your subscription ID, and store all keys in 'credentials.txt' @@ -87,7 +87,7 @@ Currently this module supports the following: - Creating an instance of Board by passing in one of the following: - An Installable, instantiated with API Key and API Secret - - By passing in an API Key, API Secret _and_ Subscription ID directly to `Board()` + - By passing in an API Key, API Secret *and* Subscription ID directly to `Board()` - By passing in an Installable where `getSubscription=False` and manually providing the Subscription ID to `Board`. The board currently has 2 methods available, the `.post()` method, which takes in a string and sends it to the board, and the `.raw()` method, which allows you to place characters precisely where you'd like them. @@ -105,7 +105,7 @@ vboard.post('Everything you can imagine is real.') The `.post()` method supports all letters and symbols that Vestaboard supports, including all letters, numbers, and symbols. In addition, you may pass in a character code in curly brackets to represent a single character or a color tile. You can view a reference of character and color codes on [Vestaboard's official website by clicking here.](https://docs.vestaboard.com/characters) -Vestaboard's API currently strips leading and trailing spaces from lines - _this includes the `{0}` character (the black tile)_. To precisely place characters, use the `.raw()` method (see below). +Vestaboard's API currently strips leading and trailing spaces from lines - *this includes the `{0}` character (the black tile)*. To precisely place characters, use the `.raw()` method (see below). ```python import vestaboard @@ -145,7 +145,7 @@ The `.raw()` method now supports padding and truncating if more or fewer than 6 You can also specify whether you'd like the padding to be added above or below your text by passing in `pad='top'` or `pad='bottom'` (only available when passing in < 6 lines). `pad='top'` will add padding above your text (your text will be at the bottom of the board), and `pad='bottom'` will add padding below your text (your text will be at the top of the board). ---- +*** To assist with character conversion, use the `Formatter` class. The `Formatter` has two public helper options: @@ -202,7 +202,7 @@ Thanks! #### [Shane Sutro][] -#### You belong here :heart: +You belong here ♥️ *Note: this project is maintaned by independent developers and is not sponsored by nor affiliated with Vestaboard, Inc. I am unable to make changes to their API or answer questions about the company, upcoming API support, or future-state plans. For questions regarding Vestaboard's API, privacy policies, or to request assistance with your board, [please get in touch with them here.](https://www.vestaboard.com/contact)*