From 7a5bb026bbea36154947caa25f10e990ee8e70d8 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Tue, 9 Feb 2021 17:33:33 -0700 Subject: [PATCH 1/7] Initialize dev branch --- vestaboard/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vestaboard/__init__.py b/vestaboard/__init__.py index 02b1768..7561d63 100644 --- a/vestaboard/__init__.py +++ b/vestaboard/__init__.py @@ -82,6 +82,7 @@ def __init__(self, apiKey=False, apiSecret=False, getSubscription=True, saveCred apiKey: String (required) - your Vestaboard API Key apiSecret: String (required) - your Vestaboard API Secret getSubscripion: Bool (optional, default True) - If you already have your subscription ID, you may pass False into this method + saveCredentials: Bool (options, default True) - Choose whether or not to store your API keys in the home directory """ self.apiKey = apiKey From 199b2c7fd8d52f94fe4d90913318526869d5a497 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Wed, 10 Feb 2021 12:22:00 -0700 Subject: [PATCH 2/7] Updating docs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6683af6..ad2dfb5 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ Once created, you will need to store your API Key and API Secret - you'll need t - Download and install into your project file - Via `pip`: -```pip install vestaboard``` +```pip3 install vestaboard``` +_Note: if using a virtual environment, use `pip` instead of `pip3`_ #### Usage From 1cf14d68c52eb8a3bff8518921528e2c671eab89 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Wed, 10 Feb 2021 15:55:24 -0700 Subject: [PATCH 3/7] Added color padding to converLine method --- tests/test_formatting.py | 54 +++++++++++++++++++++++++++++++++++++++- vestaboard/characters.py | 23 +++++++++++++++-- vestaboard/formatter.py | 53 ++++++++++++++++++++++++++++++++------- 3 files changed, 118 insertions(+), 12 deletions(-) diff --git a/tests/test_formatting.py b/tests/test_formatting.py index 85f9f6d..3a4fe68 100644 --- a/tests/test_formatting.py +++ b/tests/test_formatting.py @@ -37,6 +37,10 @@ def test_word_conversion_with_invalid_characters_fails(): with pytest.raises(Exception): Formatter().convert('test message^*', byWord=True) +def test_convert_line_fails_if_too_many_characters(): + with pytest.raises(Exception): + Formatter().convertLine('This is too many characters for a line') + def test_convert_line_with_centering(): assert len(Formatter().convertLine('test message')) == 22, 'Should return a list with 22 elements' assert Formatter().convertLine('test message') == [0, 0, 0, 0, 0, 20, 5, 19, 20, 0, 13, 5, 19, 19, 1, 7, 5, 0, 0, 0, 0, 0], 'Should add padding to reach 22 characters' @@ -52,5 +56,53 @@ def test_convert_line_right_justified(): def test_valid_characters_should_pass(): assert Formatter()._isValid('abcdefghijklmnopqrstuvwxyz1234567890 !@#$()-+&=;:"%,./?°') == True +def test_with_character_code_at_beginning_of_string(): + result = Formatter().convertLine('{23}{1} Test') + expected = [0, 0, 0, 0, 0, 0, 0, 0, 23, 1, 0, 20, 5, 19, 20, 0, 0, 0, 0, 0, 0, 0] + assert result == expected + +def test_with_character_code_at_end_of_string(): + result = Formatter().convertLine('Test {23}{1}') + expected = [0, 0, 0, 0, 0, 0, 0, 0, 20, 5, 19, 20, 0, 23, 1, 0, 0, 0, 0, 0, 0, 0] + assert result == expected + +def test_with_character_code_in_middle_of_text(): + result = Formatter().convertLine('Test {23}{1} Test') + expected = [0, 0, 0, 0, 0, 20, 5, 19, 20, 0, 23, 1, 0, 20, 5, 19, 20, 0, 0, 0, 0, 0] + assert result == expected + +def test_with_text_between_character_codes(): + result = Formatter().convertLine('{48}{3} Test {23}{1}') + expected = [0, 0, 0, 0, 0, 0, 48, 3, 0, 20, 5, 19, 20, 0, 23, 1, 0, 0, 0, 0, 0, 0] + assert result == expected + def test_invalid_characters_should_fail(): - assert Formatter()._isValid('^*') == False \ No newline at end of file + assert Formatter()._isValid('^*') == False + +def test_regex_finds_valid_character_codes(): + actual = Formatter()._getEmbeddedCharCodes('{24}{1}') + expected = ['{24}', '{1}'] + assert actual == expected + +def test_regex_returns_num_of_extra_characters(): + t1 = Formatter()._numCharacterCodes('{13}{2}') + e1 = 5 + t2 = Formatter()._numCharacterCodes('{23}{25}{25}') + e2 = 9 + t3 = Formatter()._numCharacterCodes('There are no codes') + e3 = 0 + assert t1 == e1 + assert t2 == e2 + assert t3 == e3 + +def test_formatter_accepts_padding_colors(): + t1 = Formatter().convertLine('red', color='red') + e1 = [63, 63, 63, 63, 63, 63, 63, 63, 63, 18, 5, 4, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63] + t2 = Formatter().convertLine('orange', color='orange') + e2 = [64, 64, 64, 64, 64, 64, 64, 64, 15, 18, 1, 14, 7, 5, 64, 64, 64, 64, 64, 64, 64, 64] + t3 = Formatter().convertLine('yellow', color='yellow') + e3 = [65, 65, 65, 65, 65, 65, 65, 65, 25, 5, 12, 12, 15, 23, 65, 65, 65, 65, 65, 65, 65, 65] + +def test_formatter_fails_invalid_colors(): + with pytest.raises(KeyError): + Formatter().convertLine('error', color='pink') \ No newline at end of file diff --git a/vestaboard/characters.py b/vestaboard/characters.py index c740868..b9580ed 100644 --- a/vestaboard/characters.py +++ b/vestaboard/characters.py @@ -59,5 +59,24 @@ '/': 59, '?': 60, # Missing 61 - '°': 62 - } \ No newline at end of file + '°': 62, + 63: 63, + 64: 64, + 65: 65, + 66: 66, + 67: 67, + 68: 68, + 69: 69, + 0: 0 + } + +colors = { + 'red': '{63}', + 'orange': '{64}', + 'yellow': '{65}', + 'green': '{66}', + 'blue': '{67}', + 'violet': '{68}', + 'white': '{69}', + 'black': '{00}' +} \ No newline at end of file diff --git a/vestaboard/formatter.py b/vestaboard/formatter.py index b3342ce..f949058 100644 --- a/vestaboard/formatter.py +++ b/vestaboard/formatter.py @@ -1,4 +1,5 @@ from vestaboard.characters import characters +from vestaboard.characters import colors import re class Formatter: @@ -17,9 +18,23 @@ def _raw(charList): @staticmethod def _isValid(inputString): inputString = inputString.lower() - test = "^[A-Za-z0-9!@#$\(\)\-+&=;:'\"%,./?°\s ]*(?:\{[0-9]+\})*[A-Za-z0-9!@#$\(\)\-+&=;:'\"%,./?°\s ]*$" + test = "^(?:[A-Za-z0-9!@#$\(\)\-+&=;:'\"%,./?°\s ]*(?:\{[0-9]+\})*[A-Za-z0-9!@#$\(\)\-+&=;:'\"%,./?°\s ]*)*$" return bool(re.match(test, inputString)) + + @staticmethod + def _getEmbeddedCharCodes(inputString): + test = "\{[0-9]+\}+" + + return re.findall(test, inputString) + + def _numCharacterCodes(self, inputString): + embeddedCharacterCodes = self._getEmbeddedCharCodes(inputString) + numCharacterCodes = 0 + for match in embeddedCharacterCodes: + numCharacterCodes += 2 + (len(match) - 3) + + return numCharacterCodes def convert(self, inputString, byLetter=True, byWord=False): if not self._isValid(inputString): @@ -39,20 +54,40 @@ def convert(self, inputString, byLetter=True, byWord=False): return converted - def convertLine(self, inputString, center=True, left=False, right=False): + def convertLine(self, inputString, center=True, left=False, right=False, color=' ', spaceBuffer=False): if not self._isValid(inputString): raise Exception('Your text contains one or more characters that the Vestaboard does not support.') + numCharacterCodes = self._numCharacterCodes(inputString) + if spaceBuffer: + inputString = ' ' + inputString + ' ' inputString = inputString.lower() + if color != ' ': + try: + color = colors[color] + except KeyError: + raise KeyError('Valid colors are red, orange, yellow, green, blue, violet, white, and black (default black).') converted = [] - if len(inputString) > 22: - return Exception('Convert line method takes in a string less than or equal to 22 characters.') + if len(inputString) - numCharacterCodes > 22: + raise Exception(f'Convert line method takes in a string less than or equal to 22 characters - string passed in was {len(inputString)} characters. Reduce size and try again (remember that setting spaceBuffer=True increases your line size by 2).') if left: - inputString = inputString.ljust(22) + inputString = inputString.ljust(22 + numCharacterCodes, '^') elif right: - inputString = inputString.rjust(22) + inputString = inputString.rjust(22 + numCharacterCodes, '^') elif center: - inputString = inputString.center(22) - for letter in inputString: - converted.append(characters[letter]) + inputString = inputString.center(22 + numCharacterCodes, '^') + inputString = inputString.replace('^', color) + skipTo = 0 + for index, letter in enumerate(inputString): + if index < skipTo: + continue + if letter == '{': + if inputString[index + 3] == '}': #two-digit character code like {63} + converted.append(int(inputString[index + 1: index + 3])) + skipTo = index + 4 + elif inputString[index + 2] == '}': #one-digit character code like {4} + converted.append(int(inputString[index + 1: index + 2])) + skipTo = index + 3 + else: + converted.append(characters[letter]) return converted From 0c44fc81458b1696ab6861ec7a49a26c50cde245 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Wed, 10 Feb 2021 16:23:46 -0700 Subject: [PATCH 4/7] =?UTF-8?q?=E2=9C=A8=20Updates=20to=20tests,=20fix=20p?= =?UTF-8?q?arameter=20for=20justify=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_formatting.py | 26 +++++++++++++++++++++----- vestaboard/formatter.py | 15 ++++++++++----- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/tests/test_formatting.py b/tests/test_formatting.py index 3a4fe68..d1a00b7 100644 --- a/tests/test_formatting.py +++ b/tests/test_formatting.py @@ -46,12 +46,12 @@ def test_convert_line_with_centering(): assert Formatter().convertLine('test message') == [0, 0, 0, 0, 0, 20, 5, 19, 20, 0, 13, 5, 19, 19, 1, 7, 5, 0, 0, 0, 0, 0], 'Should add padding to reach 22 characters' def test_convert_line_left_justified(): - assert len(Formatter().convertLine('Oh hi!', left=True)) == 22, 'Should return a list with 22 elements' - assert Formatter().convertLine('Oh hi!', left=True) == [15, 8, 0, 8, 9, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'Should left justify up to 22 characters' + assert len(Formatter().convertLine('Oh hi!', justify='left')) == 22, 'Should return a list with 22 elements' + assert Formatter().convertLine('Oh hi!', justify='left') == [15, 8, 0, 8, 9, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'Should left justify up to 22 characters' def test_convert_line_right_justified(): - assert len(Formatter().convertLine('Oh hi!', right=True)) == 22, 'Should return a list with 22 elements' - assert Formatter().convertLine('Oh hi!', right=True) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 8, 0, 8, 9, 37], 'Should left justify up to 22 characters' + assert len(Formatter().convertLine('Oh hi!', justify='right')) == 22, 'Should return a list with 22 elements' + assert Formatter().convertLine('Oh hi!', justify='right') == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 8, 0, 8, 9, 37], 'Should left justify up to 22 characters' def test_valid_characters_should_pass(): assert Formatter()._isValid('abcdefghijklmnopqrstuvwxyz1234567890 !@#$()-+&=;:"%,./?°') == True @@ -103,6 +103,22 @@ def test_formatter_accepts_padding_colors(): t3 = Formatter().convertLine('yellow', color='yellow') e3 = [65, 65, 65, 65, 65, 65, 65, 65, 25, 5, 12, 12, 15, 23, 65, 65, 65, 65, 65, 65, 65, 65] + assert t1 == e1 + assert t2 == e2 + assert t3 == e3 + def test_formatter_fails_invalid_colors(): with pytest.raises(KeyError): - Formatter().convertLine('error', color='pink') \ No newline at end of file + Formatter().convertLine('error', color='pink') + +def test_space_buffer_adds_spaces_where_appropriate(): + t1 = Formatter().convertLine('center', justify='center', spaceBuffer=True, color='white') + t2 = Formatter().convertLine('left', justify='left', spaceBuffer=True, color='white') + t3 = Formatter().convertLine('right', justify='right', spaceBuffer=True, color='white') + e1 = [69, 69, 69, 69, 69, 69, 69, 0, 3, 5, 14, 20, 5, 18, 0, 69, 69, 69, 69, 69, 69, 69] + e2 = [12, 5, 6, 20, 0, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69] + e3 = [69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 18, 9, 7, 8, 20] + + assert t1 == e1, 'Should add spacing on both sides of centered text' + assert t2 == e2, 'Should add spacing to the right side of left-justified text' + assert t3 == e3, 'Should add spacing to the left side of right-justified text' \ No newline at end of file diff --git a/vestaboard/formatter.py b/vestaboard/formatter.py index f949058..7315c22 100644 --- a/vestaboard/formatter.py +++ b/vestaboard/formatter.py @@ -54,12 +54,17 @@ def convert(self, inputString, byLetter=True, byWord=False): return converted - def convertLine(self, inputString, center=True, left=False, right=False, color=' ', spaceBuffer=False): + def convertLine(self, inputString, justify='center', color=' ', spaceBuffer=False): if not self._isValid(inputString): raise Exception('Your text contains one or more characters that the Vestaboard does not support.') numCharacterCodes = self._numCharacterCodes(inputString) if spaceBuffer: - inputString = ' ' + inputString + ' ' + if justify == 'left': + inputString = inputString + ' ' + elif justify == 'right': + inputString = ' ' + inputString + else: + inputString = ' ' + inputString + ' ' inputString = inputString.lower() if color != ' ': try: @@ -69,11 +74,11 @@ def convertLine(self, inputString, center=True, left=False, right=False, color=' converted = [] if len(inputString) - numCharacterCodes > 22: raise Exception(f'Convert line method takes in a string less than or equal to 22 characters - string passed in was {len(inputString)} characters. Reduce size and try again (remember that setting spaceBuffer=True increases your line size by 2).') - if left: + if justify == 'left': inputString = inputString.ljust(22 + numCharacterCodes, '^') - elif right: + elif justify == 'right': inputString = inputString.rjust(22 + numCharacterCodes, '^') - elif center: + elif justify == 'center': inputString = inputString.center(22 + numCharacterCodes, '^') inputString = inputString.replace('^', color) skipTo = 0 From 5df43796c981c15d85b431fe6abb77d82e7b5cfd Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Fri, 12 Feb 2021 07:27:06 -0700 Subject: [PATCH 5/7] =?UTF-8?q?=E2=81=89=EF=B8=8F=20De-complicated=20the?= =?UTF-8?q?=20Formatter=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vestaboard/formatter.py | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/vestaboard/formatter.py b/vestaboard/formatter.py index 7315c22..4958204 100644 --- a/vestaboard/formatter.py +++ b/vestaboard/formatter.py @@ -21,7 +21,7 @@ def _isValid(inputString): test = "^(?:[A-Za-z0-9!@#$\(\)\-+&=;:'\"%,./?°\s ]*(?:\{[0-9]+\})*[A-Za-z0-9!@#$\(\)\-+&=;:'\"%,./?°\s ]*)*$" return bool(re.match(test, inputString)) - + @staticmethod def _getEmbeddedCharCodes(inputString): test = "\{[0-9]+\}+" @@ -59,12 +59,7 @@ def convertLine(self, inputString, justify='center', color=' ', spaceBuffer=Fals raise Exception('Your text contains one or more characters that the Vestaboard does not support.') numCharacterCodes = self._numCharacterCodes(inputString) if spaceBuffer: - if justify == 'left': - inputString = inputString + ' ' - elif justify == 'right': - inputString = ' ' + inputString - else: - inputString = ' ' + inputString + ' ' + inputString = self._addSpaceBuffer(inputString, justify) inputString = inputString.lower() if color != ' ': try: @@ -74,13 +69,8 @@ def convertLine(self, inputString, justify='center', color=' ', spaceBuffer=Fals converted = [] if len(inputString) - numCharacterCodes > 22: raise Exception(f'Convert line method takes in a string less than or equal to 22 characters - string passed in was {len(inputString)} characters. Reduce size and try again (remember that setting spaceBuffer=True increases your line size by 2).') - if justify == 'left': - inputString = inputString.ljust(22 + numCharacterCodes, '^') - elif justify == 'right': - inputString = inputString.rjust(22 + numCharacterCodes, '^') - elif justify == 'center': - inputString = inputString.center(22 + numCharacterCodes, '^') - inputString = inputString.replace('^', color) + inputString = self._justifyContent(inputString, justify, numCharacterCodes, color) + skipTo = 0 for index, letter in enumerate(inputString): if index < skipTo: @@ -96,3 +86,25 @@ def convertLine(self, inputString, justify='center', color=' ', spaceBuffer=Fals converted.append(characters[letter]) return converted + + @staticmethod + def _addSpaceBuffer(inputString, justify): + if justify == 'left': + return inputString + ' ' + elif justify == 'right': + return ' ' + inputString + else: + return ' ' + inputString + ' ' + + @staticmethod + def _justifyContent(inputString, justify, numCharacterCodes, color): + if justify == 'left': + inputString = inputString.ljust(22 + numCharacterCodes, '^') + elif justify == 'right': + inputString = inputString.rjust(22 + numCharacterCodes, '^') + elif justify == 'center': + inputString = inputString.center(22 + numCharacterCodes, '^') + inputString = inputString.replace('^', color) + + return inputString + From eda9fb8b9eb1babc666a468b7c0bdb98b7420c2c Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Fri, 12 Feb 2021 07:32:41 -0700 Subject: [PATCH 6/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Updating=20version=20n?= =?UTF-8?q?umber=20in=20setup.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d106e0a..290af81 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="Vestaboard", - version="0.3.1", + version="0.3.2", author="Shane Sutro", author_email="shane@shanesutro.com", description="A Vestaboard Wrapper", From 1d6c4cf30a94070591b0f76eaf71521816e63e77 Mon Sep 17 00:00:00 2001 From: Shane Sutro Date: Fri, 12 Feb 2021 07:35:12 -0700 Subject: [PATCH 7/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Updating=20version=20n?= =?UTF-8?q?umber=20to=200.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 290af81..58619d2 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="Vestaboard", - version="0.3.2", + version="0.4.0", author="Shane Sutro", author_email="shane@shanesutro.com", description="A Vestaboard Wrapper",