From 76e3894ca2033ac3df1b4f3ddbf9d5e50f993c0f Mon Sep 17 00:00:00 2001 From: dherrada Date: Sun, 15 Mar 2020 17:54:34 -0400 Subject: [PATCH] Ran black, updated to pylint 2.x --- .github/workflows/build.yml | 2 +- adafruit_pyportal.py | 376 ++++++++++++++++++++------------ docs/conf.py | 140 +++++++----- examples/pyportal_simpletest.py | 4 +- setup.py | 64 +++--- 5 files changed, 358 insertions(+), 228 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fff3aa9..1dad804 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: source actions-ci/install.sh - name: Pip install pylint, black, & Sphinx run: | - pip install --force-reinstall pylint==1.9.2 black==19.10b0 Sphinx sphinx-rtd-theme + pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme - name: Library version run: git describe --dirty --always --tags - name: PyLint diff --git a/adafruit_pyportal.py b/adafruit_pyportal.py index 257a2bf..03df426 100644 --- a/adafruit_pyportal.py +++ b/adafruit_pyportal.py @@ -64,24 +64,30 @@ import adafruit_sdcard - -if hasattr(board, 'TOUCH_XL'): +if hasattr(board, "TOUCH_XL"): import adafruit_touchscreen -elif hasattr(board, 'BUTTON_CLOCK'): +elif hasattr(board, "BUTTON_CLOCK"): from adafruit_cursorcontrol.cursorcontrol import Cursor from adafruit_cursorcontrol.cursorcontrol_cursormanager import CursorManager try: - from adafruit_display_text.text_area import TextArea # pylint: disable=unused-import - print("*** WARNING ***\nPlease update your library bundle to the latest 'adafruit_display_text' version as we've deprecated 'text_area' in favor of 'label'") # pylint: disable=line-too-long + from adafruit_display_text.text_area import ( # pylint: disable=unused-import + TextArea, + ) + + print( + "*** WARNING ***\nPlease update your library bundle to the latest 'adafruit_display_text' version as we've deprecated 'text_area' in favor of 'label'" # pylint: disable=line-too-long + ) except ImportError: from adafruit_display_text.Label import Label try: from secrets import secrets except ImportError: - print("""WiFi settings are kept in secrets.py, please add them there! -the secrets dictionary must contain 'ssid' and 'password' at a minimum""") + print( + """WiFi settings are kept in secrets.py, please add them there! +the secrets dictionary must contain 'ssid' and 'password' at a minimum""" + ) raise __version__ = "0.0.0-auto.0" @@ -92,16 +98,21 @@ # you'll need to pass in an io username, width, height, format (bit depth), io key, and then url! IMAGE_CONVERTER_SERVICE = "https://io.adafruit.com/api/v2/%s/integrations/image-formatter?x-aio-key=%s&width=%d&height=%d&output=BMP%d&url=%s" # you'll need to pass in an io username and key -TIME_SERVICE = "https://io.adafruit.com/api/v2/%s/integrations/time/strftime?x-aio-key=%s" +TIME_SERVICE = ( + "https://io.adafruit.com/api/v2/%s/integrations/time/strftime?x-aio-key=%s" +) # our strftime is %Y-%m-%d %H:%M:%S.%L %j %u %z %Z see http://strftime.net/ for decoding details # See https://apidock.com/ruby/DateTime/strftime for full options -TIME_SERVICE_STRFTIME = '&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S.%25L+%25j+%25u+%25z+%25Z' +TIME_SERVICE_STRFTIME = ( + "&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S.%25L+%25j+%25u+%25z+%25Z" +) LOCALFILE = "local.txt" # pylint: enable=line-too-long class Fake_Requests: """For faking 'requests' using a local file instead of the network.""" + def __init__(self, filename): self._filename = filename with open(filename, "r") as file: @@ -109,7 +120,8 @@ def __init__(self, filename): def json(self): """json parsed version for local requests.""" - import json + import json # pylint: disable=import-outside-toplevel + return json.loads(self.text) @@ -162,24 +174,50 @@ class PyPortal: :param debug: Turn on debug print outs. Defaults to False. """ + # pylint: disable=too-many-instance-attributes, too-many-locals, too-many-branches, too-many-statements - def __init__(self, *, url=None, headers=None, json_path=None, regexp_path=None, - default_bg=0x000000, status_neopixel=None, - text_font=None, text_position=None, text_color=0x808080, - text_wrap=False, text_maxlen=0, text_transform=None, - json_transform=None, image_json_path=None, - image_resize=None, image_position=None, image_dim_json_path=None, - caption_text=None, caption_font=None, caption_position=None, - caption_color=0x808080, image_url_path=None, - success_callback=None, esp=None, external_spi=None, debug=False): + def __init__( + self, + *, + url=None, + headers=None, + json_path=None, + regexp_path=None, + default_bg=0x000000, + status_neopixel=None, + text_font=None, + text_position=None, + text_color=0x808080, + text_wrap=False, + text_maxlen=0, + text_transform=None, + json_transform=None, + image_json_path=None, + image_resize=None, + image_position=None, + image_dim_json_path=None, + caption_text=None, + caption_font=None, + caption_position=None, + caption_color=0x808080, + image_url_path=None, + success_callback=None, + esp=None, + external_spi=None, + debug=False + ): self._debug = debug try: - if hasattr(board, 'TFT_BACKLIGHT'): - self._backlight = pulseio.PWMOut(board.TFT_BACKLIGHT) # pylint: disable=no-member - elif hasattr(board, 'TFT_LITE'): - self._backlight = pulseio.PWMOut(board.TFT_LITE) # pylint: disable=no-member + if hasattr(board, "TFT_BACKLIGHT"): + self._backlight = pulseio.PWMOut( + board.TFT_BACKLIGHT + ) # pylint: disable=no-member + elif hasattr(board, "TFT_LITE"): + self._backlight = pulseio.PWMOut( + board.TFT_LITE + ) # pylint: disable=no-member except ValueError: self._backlight = None self.set_backlight(1.0) # turn on backlight @@ -226,7 +264,7 @@ def __init__(self, *, url=None, headers=None, json_path=None, regexp_path=None, os.stat(bootscreen) board.DISPLAY.show(self.splash) for i in range(100, -1, -1): # dim down - self.set_backlight(i/100) + self.set_backlight(i / 100) time.sleep(0.005) self.set_background(bootscreen) try: @@ -234,30 +272,30 @@ def __init__(self, *, url=None, headers=None, json_path=None, regexp_path=None, except AttributeError: board.DISPLAY.wait_for_frame() for i in range(100): # dim up - self.set_backlight(i/100) + self.set_backlight(i / 100) time.sleep(0.005) time.sleep(2) except OSError: - pass # they removed it, skip! + pass # they removed it, skip! self._speaker_enable = DigitalInOut(board.SPEAKER_ENABLE) self._speaker_enable.switch_to_output(False) - if hasattr(board, 'AUDIO_OUT'): + if hasattr(board, "AUDIO_OUT"): self.audio = audioio.AudioOut(board.AUDIO_OUT) - elif hasattr(board, 'SPEAKER'): + elif hasattr(board, "SPEAKER"): self.audio = audioio.AudioOut(board.SPEAKER) else: - raise AttributeError('Board does not have a builtin speaker!') + raise AttributeError("Board does not have a builtin speaker!") try: self.play_file("pyportal_startup.wav") except OSError: - pass # they deleted the file, no biggie! + pass # they deleted the file, no biggie! if esp: # If there was a passed ESP Object if self._debug: print("Passed ESP32 to PyPortal") self._esp = esp - if external_spi: #If SPI Object Passed + if external_spi: # If SPI Object Passed spi = external_spi else: # Else: Make ESP32 connection spi = busio.SPI(board.SCK, board.MOSI, board.MISO) @@ -270,10 +308,11 @@ def __init__(self, *, url=None, headers=None, json_path=None, regexp_path=None, esp32_cs = DigitalInOut(board.ESP_CS) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) - self._esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, - esp32_reset, esp32_gpio0) - #self._esp._debug = 1 - for _ in range(3): # retries + self._esp = adafruit_esp32spi.ESP_SPIcontrol( + spi, esp32_cs, esp32_ready, esp32_reset, esp32_gpio0 + ) + # self._esp._debug = 1 + for _ in range(3): # retries try: print("ESP firmware:", self._esp.firmware_version) break @@ -378,29 +417,37 @@ def __init__(self, *, url=None, headers=None, json_path=None, regexp_path=None, if not self._image_position: self._image_position = (0, 0) # default to top corner if not self._image_resize: - self._image_resize = (board.DISPLAY.width, - board.DISPLAY.height) # default to full screen - if hasattr(board, 'TOUCH_XL'): + self._image_resize = ( + board.DISPLAY.width, + board.DISPLAY.height, + ) # default to full screen + if hasattr(board, "TOUCH_XL"): if self._debug: print("Init touchscreen") # pylint: disable=no-member - self.touchscreen = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR, - board.TOUCH_YD, board.TOUCH_YU, - calibration=((5200, 59000), - (5800, 57000)), - size=(board.DISPLAY.width, - board.DISPLAY.height)) + self.touchscreen = adafruit_touchscreen.Touchscreen( + board.TOUCH_XL, + board.TOUCH_XR, + board.TOUCH_YD, + board.TOUCH_YU, + calibration=((5200, 59000), (5800, 57000)), + size=(board.DISPLAY.width, board.DISPLAY.height), + ) # pylint: enable=no-member self.set_backlight(1.0) # turn on backlight - elif hasattr(board, 'BUTTON_CLOCK'): + elif hasattr(board, "BUTTON_CLOCK"): if self._debug: print("Init cursor") - self.mouse_cursor = Cursor(board.DISPLAY, display_group=self.splash, cursor_speed=8) + self.mouse_cursor = Cursor( + board.DISPLAY, display_group=self.splash, cursor_speed=8 + ) self.mouse_cursor.hide() self.cursor = CursorManager(self.mouse_cursor) else: - raise AttributeError('PyPortal module requires either a touchscreen or gamepad.') + raise AttributeError( + "PyPortal module requires either a touchscreen or gamepad." + ) gc.collect() @@ -428,30 +475,40 @@ def set_background(self, file_or_color, position=None): return # we're done, no background desired if self._bg_file: self._bg_file.close() - if isinstance(file_or_color, str): # its a filenme: + if isinstance(file_or_color, str): # its a filenme: self._bg_file = open(file_or_color, "rb") background = displayio.OnDiskBitmap(self._bg_file) try: - self._bg_sprite = displayio.TileGrid(background, - pixel_shader=displayio.ColorConverter(), - position=position) + self._bg_sprite = displayio.TileGrid( + background, + pixel_shader=displayio.ColorConverter(), + position=position, + ) except TypeError: - self._bg_sprite = displayio.TileGrid(background, - pixel_shader=displayio.ColorConverter(), - x=position[0], y=position[1]) + self._bg_sprite = displayio.TileGrid( + background, + pixel_shader=displayio.ColorConverter(), + x=position[0], + y=position[1], + ) elif isinstance(file_or_color, int): # Make a background color fill - color_bitmap = displayio.Bitmap(board.DISPLAY.width, board.DISPLAY.height, 1) + color_bitmap = displayio.Bitmap( + board.DISPLAY.width, board.DISPLAY.height, 1 + ) color_palette = displayio.Palette(1) color_palette[0] = file_or_color try: - self._bg_sprite = displayio.TileGrid(color_bitmap, - pixel_shader=color_palette, - position=(0, 0)) + self._bg_sprite = displayio.TileGrid( + color_bitmap, pixel_shader=color_palette, position=(0, 0) + ) except TypeError: - self._bg_sprite = displayio.TileGrid(color_bitmap, - pixel_shader=color_palette, - x=position[0], y=position[1]) + self._bg_sprite = displayio.TileGrid( + color_bitmap, + pixel_shader=color_palette, + x=position[0], + y=position[1], + ) else: raise RuntimeError("Unknown type of background") self._bg_group.append(self._bg_sprite) @@ -487,7 +544,7 @@ def preload_font(self, glyphs=None): """ # pylint: enable=line-too-long if not glyphs: - glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-!,. "\'?!' + glyphs = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-!,. \"'?!" print("Preloading font glyphs:", glyphs) if self._text_font: self._text_font.load_glyphs(glyphs) @@ -510,7 +567,9 @@ def set_caption(self, caption_text, caption_position, caption_color): return # nothing to do! if self._caption: - self._caption._update_text(str(caption_text)) # pylint: disable=protected-access + self._caption._update_text( # pylint: disable=protected-access + str(caption_text) + ) try: board.DISPLAY.refresh(target_frames_per_second=60) except AttributeError: @@ -534,7 +593,7 @@ def set_text(self, val, index=0): if self._text_font: string = str(val) if self._text_maxlen[index]: - string = string[:self._text_maxlen[index]] + string = string[: self._text_maxlen[index]] if self._text[index]: # print("Replacing text area with :", string) # self._text[index].text = string @@ -607,16 +666,18 @@ def get_local_time(self, location=None): self._connect_esp() api_url = None try: - aio_username = secrets['aio_username'] - aio_key = secrets['aio_key'] + aio_username = secrets["aio_username"] + aio_key = secrets["aio_key"] except KeyError: - raise KeyError("\n\nOur time service requires a login/password to rate-limit. Please register for a free adafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'")# pylint: disable=line-too-long + raise KeyError( + "\n\nOur time service requires a login/password to rate-limit. Please register for a free adafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'" # pylint: disable=line-too-long + ) - location = secrets.get('timezone', location) + location = secrets.get("timezone", location) if location: print("Getting time for timezone", location) api_url = (TIME_SERVICE + "&tz=%s") % (aio_username, aio_key, location) - else: # we'll try to figure it out from the IP address + else: # we'll try to figure it out from the IP address print("Getting time from IP address") api_url = TIME_SERVICE % (aio_username, aio_key) api_url += TIME_SERVICE_STRFTIME @@ -627,19 +688,22 @@ def get_local_time(self, location=None): if self._debug: print("Time request: ", api_url) print("Time reply: ", response.text) - times = response.text.split(' ') + times = response.text.split(" ") the_date = times[0] the_time = times[1] year_day = int(times[2]) week_day = int(times[3]) is_dst = None # no way to know yet except KeyError: - raise KeyError("Was unable to lookup the time, try setting secrets['timezone'] according to http://worldtimeapi.org/timezones") # pylint: disable=line-too-long - year, month, mday = [int(x) for x in the_date.split('-')] - the_time = the_time.split('.')[0] - hours, minutes, seconds = [int(x) for x in the_time.split(':')] - now = time.struct_time((year, month, mday, hours, minutes, seconds, week_day, year_day, - is_dst)) + raise KeyError( + "Was unable to lookup the time, try setting secrets['timezone'] according to http://worldtimeapi.org/timezones" # pylint: disable=line-too-long + ) + year, month, mday = [int(x) for x in the_date.split("-")] + the_time = the_time.split(".")[0] + hours, minutes, seconds = [int(x) for x in the_time.split(":")] + now = time.struct_time( + (year, month, mday, hours, minutes, seconds, week_day, year_day, is_dst) + ) print(now) rtc.RTC().datetime = now @@ -663,7 +727,7 @@ def wget(self, url, filename, *, chunk_size=12000): if self._debug: print(r.headers) - content_length = int(r.headers['content-length']) + content_length = int(r.headers["content-length"]) remaining = content_length print("Saving data to ", filename) stamp = time.monotonic() @@ -673,9 +737,12 @@ def wget(self, url, filename, *, chunk_size=12000): remaining -= len(i) file.write(i) if self._debug: - print("Read %d bytes, %d remaining" % (content_length-remaining, remaining)) + print( + "Read %d bytes, %d remaining" + % (content_length - remaining, remaining) + ) else: - print(".", end='') + print(".", end="") if not remaining: break self.neo_status((100, 100, 0)) @@ -683,7 +750,9 @@ def wget(self, url, filename, *, chunk_size=12000): r.close() stamp = time.monotonic() - stamp - print("Created file of %d bytes in %0.1f seconds" % (os.stat(filename)[6], stamp)) + print( + "Created file of %d bytes in %0.1f seconds" % (os.stat(filename)[6], stamp) + ) self.neo_status((0, 0, 0)) if not content_length == os.stat(filename)[6]: raise RuntimeError @@ -692,16 +761,16 @@ def _connect_esp(self): self.neo_status((0, 0, 100)) while not self._esp.is_connected: # secrets dictionary must contain 'ssid' and 'password' at a minimum - print("Connecting to AP", secrets['ssid']) - if secrets['ssid'] == 'CHANGE ME' or secrets['password'] == 'CHANGE ME': - change_me = "\n"+"*"*45 + print("Connecting to AP", secrets["ssid"]) + if secrets["ssid"] == "CHANGE ME" or secrets["password"] == "CHANGE ME": + change_me = "\n" + "*" * 45 change_me += "\nPlease update the 'secrets.py' file on your\n" change_me += "CIRCUITPY drive to include your local WiFi\n" change_me += "access point SSID name in 'ssid' and SSID\n" change_me += "password in 'password'. Then save to reload!\n" - change_me += "*"*45 + change_me += "*" * 45 raise OSError(change_me) - self.neo_status((100, 0, 0)) # red = not connected + self.neo_status((100, 0, 0)) # red = not connected try: self._esp.connect(secrets) except RuntimeError as error: @@ -715,14 +784,22 @@ def image_converter_url(image_url, width, height, color_depth=16): with the given width and height. aio_username and aio_key must be set in secrets.""" try: - aio_username = secrets['aio_username'] - aio_key = secrets['aio_key'] + aio_username = secrets["aio_username"] + aio_key = secrets["aio_key"] except KeyError: - raise KeyError("\n\nOur image converter service require a login/password to rate-limit. Please register for a free adafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'")# pylint: disable=line-too-long + raise KeyError( + "\n\nOur image converter service require a login/password to rate-limit. Please register for a free adafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'" # pylint: disable=line-too-long + ) + + return IMAGE_CONVERTER_SERVICE % ( + aio_username, + aio_key, + width, + height, + color_depth, + image_url, + ) - return IMAGE_CONVERTER_SERVICE % (aio_username, aio_key, - width, height, - color_depth, image_url) def sd_check(self): """Returns True if there is an SD card preset and False if there is no SD card. The _sdcard value is set in _init @@ -742,12 +819,16 @@ def push_to_io(self, feed_key, data): # pylint: enable=line-too-long try: - aio_username = secrets['aio_username'] - aio_key = secrets['aio_key'] + aio_username = secrets["aio_username"] + aio_key = secrets["aio_key"] except KeyError: - raise KeyError("Adafruit IO secrets are kept in secrets.py, please add them there!\n\n") + raise KeyError( + "Adafruit IO secrets are kept in secrets.py, please add them there!\n\n" + ) - wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(self._esp, secrets, None) + wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager( + self._esp, secrets, None + ) io_client = IO_HTTP(aio_username, aio_key, wifi) while True: @@ -763,12 +844,12 @@ def push_to_io(self, feed_key, data): while True: try: - io_client.send_data(feed_id['key'], data) + io_client.send_data(feed_id["key"], data) except RuntimeError as exception: print("An error occured, retrying! 2 -", exception) continue except NameError as exception: - print(feed_id['key'], data, exception) + print(feed_id["key"], data, exception) continue break @@ -795,12 +876,12 @@ def fetch(self, refresh_url=None): if not r: self._connect_esp() # great, lets get the data - print("Retrieving data...", end='') - self.neo_status((100, 100, 0)) # yellow = fetching data + print("Retrieving data...", end="") + self.neo_status((100, 100, 0)) # yellow = fetching data gc.collect() r = requests.get(self._url, headers=self._headers, timeout=10) gc.collect() - self.neo_status((0, 0, 100)) # green = got data + self.neo_status((0, 0, 100)) # green = got data print("Reply is OK!") if self._debug: @@ -811,14 +892,14 @@ def fetch(self, refresh_url=None): gc.collect() json_out = r.json() gc.collect() - except ValueError: # failed to parse? + except ValueError: # failed to parse? print("Couldn't parse json: ", r.text) raise except MemoryError: supervisor.reload() if self._regexp_path: - import re + import re # pylint: disable=import-outside-toplevel if self._image_url_path: image_url = self._image_url_path @@ -856,8 +937,12 @@ def fetch(self, refresh_url=None): iwidth = 0 iheight = 0 if self._image_dim_json_path: - iwidth = int(PyPortal._json_traverse(json_out, self._image_dim_json_path[0])) - iheight = int(PyPortal._json_traverse(json_out, self._image_dim_json_path[1])) + iwidth = int( + PyPortal._json_traverse(json_out, self._image_dim_json_path[0]) + ) + iheight = int( + PyPortal._json_traverse(json_out, self._image_dim_json_path[1]) + ) print("image dim:", iwidth, iheight) # we're done with the requests object, lets delete it so we can do more! @@ -869,20 +954,24 @@ def fetch(self, refresh_url=None): try: print("original URL:", image_url) if iwidth < iheight: - image_url = self.image_converter_url(image_url, - int(self._image_resize[1] - * self._image_resize[1] - / self._image_resize[0]), - self._image_resize[1]) + image_url = self.image_converter_url( + image_url, + int( + self._image_resize[1] + * self._image_resize[1] + / self._image_resize[0] + ), + self._image_resize[1], + ) else: - image_url = self.image_converter_url(image_url, - self._image_resize[0], - self._image_resize[1]) + image_url = self.image_converter_url( + image_url, self._image_resize[0], self._image_resize[1] + ) print("convert URL:", image_url) # convert image to bitmap and cache - #print("**not actually wgetting**") + # print("**not actually wgetting**") filename = "/cache.bmp" - chunk_size = 4096 # default chunk size is 12K (for QSPI) + chunk_size = 4096 # default chunk size is 12K (for QSPI) if self._sdcard: filename = "/sd" + filename chunk_size = 512 # current bug in big SD writes -> stick to 1 block @@ -890,18 +979,26 @@ def fetch(self, refresh_url=None): self.wget(image_url, filename, chunk_size=chunk_size) except OSError as error: print(error) - raise OSError("""\n\nNo writable filesystem found for saving datastream. Insert an SD card or set internal filesystem to be unsafe by setting 'disable_concurrent_write_protection' in the mount options in boot.py""") # pylint: disable=line-too-long + raise OSError( + """\n\nNo writable filesystem found for saving datastream. Insert an SD card or set internal filesystem to be unsafe by setting 'disable_concurrent_write_protection' in the mount options in boot.py""" # pylint: disable=line-too-long + ) except RuntimeError as error: print(error) raise RuntimeError("wget didn't write a complete file") if iwidth < iheight: - pwidth = int(self._image_resize[1] * - self._image_resize[1] / self._image_resize[0]) - self.set_background(filename, - (self._image_position[0] - + int((self._image_resize[0] - - pwidth) / 2), - self._image_position[1])) + pwidth = int( + self._image_resize[1] + * self._image_resize[1] + / self._image_resize[0] + ) + self.set_background( + filename, + ( + self._image_position[0] + + int((self._image_resize[0] - pwidth) / 2), + self._image_position[1], + ), + ) else: self.set_background(filename, self._image_position) @@ -927,20 +1024,22 @@ def fetch(self, refresh_url=None): try: string = "{:,d}".format(int(values[i])) except (TypeError, ValueError): - string = values[i] # ok its a string + string = values[i] # ok its a string if self._debug: print("Drawing text", string) if self._text_wrap[i]: if self._debug: print("Wrapping text") lines = PyPortal.wrap_nicely(string, self._text_wrap[i]) - string = '\n'.join(lines) + string = "\n".join(lines) self.set_text(string, index=i) if len(values) == 1: return values[0] return values - def show_QR(self, qr_data, *, qr_size=1, x=0, y=0, hide_background=False): # pylint: disable=invalid-name + def show_QR( + self, qr_data, *, qr_size=1, x=0, y=0, hide_background=False + ): # pylint: disable=invalid-name """Display a QR code on the TFT :param qr_data: The data for the QR code. @@ -950,7 +1049,8 @@ def show_QR(self, qr_data, *, qr_size=1, x=0, y=0, hide_background=False): # py :param hide_background: Show the QR code on a black background if True. """ - import adafruit_miniqr + import adafruit_miniqr # pylint: disable=import-outside-toplevel + # generate the QR code qrcode = adafruit_miniqr.QRCode() qrcode.add_data(qr_data) @@ -963,21 +1063,23 @@ def show_QR(self, qr_data, *, qr_size=1, x=0, y=0, hide_background=False): # py # pylint: disable=invalid-name # bitmap the size of the matrix, plus border, monochrome (2 colors) - qr_bitmap = displayio.Bitmap(qrcode.matrix.width + 2, qrcode.matrix.height + 2, 2) + qr_bitmap = displayio.Bitmap( + qrcode.matrix.width + 2, qrcode.matrix.height + 2, 2 + ) for i in range(qr_bitmap.width * qr_bitmap.height): qr_bitmap[i] = 0 # transcribe QR code into bitmap for xx in range(qrcode.matrix.width): for yy in range(qrcode.matrix.height): - qr_bitmap[xx+1, yy+1] = 1 if qrcode.matrix[xx, yy] else 0 + qr_bitmap[xx + 1, yy + 1] = 1 if qrcode.matrix[xx, yy] else 0 # display the QR code qr_sprite = displayio.TileGrid(qr_bitmap, pixel_shader=palette) if self._qr_group: try: self._qr_group.pop() - except IndexError: # later test if empty + except IndexError: # later test if empty pass else: self._qr_group = displayio.Group() @@ -990,7 +1092,7 @@ def show_QR(self, qr_data, *, qr_size=1, x=0, y=0, hide_background=False): # py board.DISPLAY.show(self._qr_group) self._qr_only = hide_background - def hide_QR(self): # pylint: disable=invalid-name + def hide_QR(self): # pylint: disable=invalid-name """Clear any QR codes that are currently on the screen """ @@ -999,7 +1101,7 @@ def hide_QR(self): # pylint: disable=invalid-name else: try: self._qr_group.pop() - except (IndexError, AttributeError): # later test if empty + except (IndexError, AttributeError): # later test if empty pass # return a list of lines with wordwrapping @@ -1011,17 +1113,17 @@ def wrap_nicely(string, max_chars): :param int max_chars: The maximum number of characters on a line before wrapping. """ - string = string.replace('\n', '').replace('\r', '') # strip confusing newlines - words = string.split(' ') + string = string.replace("\n", "").replace("\r", "") # strip confusing newlines + words = string.split(" ") the_lines = [] the_line = "" for w in words: - if len(the_line+' '+w) <= max_chars: - the_line += ' '+w + if len(the_line + " " + w) <= max_chars: + the_line += " " + w else: the_lines.append(the_line) - the_line = ''+w - if the_line: # last line remaining + the_line = "" + w + if the_line: # last line remaining the_lines.append(the_line) # remove first space from first line: the_lines[0] = the_lines[0][1:] diff --git a/docs/conf.py b/docs/conf.py index ba65728..6341719 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,8 @@ import os import sys -sys.path.insert(0, os.path.abspath('..')) + +sys.path.insert(0, os.path.abspath("..")) # -- General configuration ------------------------------------------------ @@ -10,46 +11,67 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.napoleon', - 'sphinx.ext.todo', + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.todo", ] # TODO: Please Read! # Uncomment the below if you use native CircuitPython modules such as # digitalio, micropython and busio. List the modules you use. Without it, the # autodoc module docs will fail to generate with a warning. -autodoc_mock_imports = ["rtc", "supervisor", "pulseio", "audioio", "displayio", "neopixel", - "microcontroller", "adafruit_touchscreen", "adafruit_bitmap_font", - "adafruit_display_text", "adafruit_esp32spi", "secrets", - "adafruit_sdcard", "storage", "adafruit_io", "adafruit_cursorcontrol", - "adafruit_requests"] +autodoc_mock_imports = [ + "rtc", + "supervisor", + "pulseio", + "audioio", + "displayio", + "neopixel", + "microcontroller", + "adafruit_touchscreen", + "adafruit_bitmap_font", + "adafruit_display_text", + "adafruit_esp32spi", + "secrets", + "adafruit_sdcard", + "storage", + "adafruit_io", + "adafruit_cursorcontrol", + "adafruit_requests", +] -intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'BusDevice': ('https://circuitpython.readthedocs.io/projects/busdevice/en/latest/', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} +intersphinx_mapping = { + "python": ("https://docs.python.org/3.4", None), + "BusDevice": ( + "https://circuitpython.readthedocs.io/projects/busdevice/en/latest/", + None, + ), + "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), +} # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'Adafruit PyPortal Library' -copyright = u'2019 Limor Fried' -author = u'Limor Fried' +project = u"Adafruit PyPortal Library" +copyright = u"2019 Limor Fried" +author = u"Limor Fried" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'1.0' +version = u"1.0" # The full version, including alpha/beta/rc tags. -release = u'1.0' +release = u"1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -61,7 +83,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -73,7 +95,7 @@ add_function_parentheses = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -88,59 +110,62 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" if not on_rtd: # only import and set the theme if we're building docs locally try: import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.'] + + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] except: - html_theme = 'default' - html_theme_path = ['.'] + html_theme = "default" + html_theme_path = ["."] else: - html_theme_path = ['.'] + html_theme_path = ["."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # -html_favicon = '_static/favicon.ico' +html_favicon = "_static/favicon.ico" # Output file base name for HTML help builder. -htmlhelp_basename = 'AdafruitPyportalLibrarydoc' +htmlhelp_basename = "AdafruitPyportalLibrarydoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AdafruitPyPortalLibrary.tex', u'AdafruitPyPortal Library Documentation', - author, 'manual'), + ( + master_doc, + "AdafruitPyPortalLibrary.tex", + u"AdafruitPyPortal Library Documentation", + author, + "manual", + ), ] # -- Options for manual page output --------------------------------------- @@ -148,8 +173,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'AdafruitPyPortallibrary', u'Adafruit PyPortal Library Documentation', - [author], 1) + ( + master_doc, + "AdafruitPyPortallibrary", + u"Adafruit PyPortal Library Documentation", + [author], + 1, + ) ] # -- Options for Texinfo output ------------------------------------------- @@ -158,7 +188,13 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'AdafruitPyPortalLibrary', u'Adafruit PyPortal Library Documentation', - author, 'AdafruitPyPortalLibrary', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "AdafruitPyPortalLibrary", + u"Adafruit PyPortal Library Documentation", + author, + "AdafruitPyPortalLibrary", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/examples/pyportal_simpletest.py b/examples/pyportal_simpletest.py index 7b87fdc..14d1514 100644 --- a/examples/pyportal_simpletest.py +++ b/examples/pyportal_simpletest.py @@ -17,6 +17,6 @@ data = pyportal.fetch() # Print out what we got -print('-'*40) +print("-" * 40) print(data) -print('-'*40) +print("-" * 40) diff --git a/setup.py b/setup.py index b0452d0..a31e056 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,7 @@ """ from setuptools import setup, find_packages + # To use a consistent encoding from codecs import open from os import path @@ -13,58 +14,49 @@ here = path.abspath(path.dirname(__file__)) # Get the long description from the README file -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: +with open(path.join(here, "README.rst"), encoding="utf-8") as f: long_description = f.read() setup( - name='adafruit-circuitpython-pyportal', - + name="adafruit-circuitpython-pyportal", use_scm_version=True, - setup_requires=['setuptools_scm'], - - description='CircuitPython driver for Adafruit PyPortal.', + setup_requires=["setuptools_scm"], + description="CircuitPython driver for Adafruit PyPortal.", long_description=long_description, - long_description_content_type='text/x-rst', - + long_description_content_type="text/x-rst", # The project's main homepage. - url='https://github.com/adafruit/Adafruit_CircuitPython_PyPortal', - + url="https://github.com/adafruit/Adafruit_CircuitPython_PyPortal", # Author details - author='Adafruit Industries', - author_email='circuitpython@adafruit.com', - + author="Adafruit Industries", + author_email="circuitpython@adafruit.com", install_requires=[ - 'Adafruit-Blinka', - 'adafruit-circuitpython-busdevice', - 'adafruit-circuitpython-touchscreen', - 'adafruit-circuitpython-esp32spi', - 'adafruit-circuitpython-bitmapfont', - 'adafruit-circuitpython-displaytext', - 'adafruit-circuitpython-neopixel' + "Adafruit-Blinka", + "adafruit-circuitpython-busdevice", + "adafruit-circuitpython-touchscreen", + "adafruit-circuitpython-esp32spi", + "adafruit-circuitpython-bitmapfont", + "adafruit-circuitpython-displaytext", + "adafruit-circuitpython-neopixel", ], - # Choose your license - license='MIT', - + license="MIT", # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries', - 'Topic :: System :: Hardware', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Hardware", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", ], - # What does your project relate to? - keywords='adafruit blinka circuitpython micropython pyportal iot internet display portal ' - 'wifi', - + keywords="adafruit blinka circuitpython micropython pyportal iot internet display portal " + "wifi", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER, # CHANGE `py_modules=['...']` TO `packages=['...']` - py_modules=['adafruit_pyportal'], + py_modules=["adafruit_pyportal"], )