Skip to content

Commit 6984552

Browse files
authoredMay 16, 2025··
Merge pull request #45 from adafruit/use_ruff
change to ruff
2 parents 890a5e5 + 9564215 commit 6984552

File tree

20 files changed

+236
-595
lines changed

20 files changed

+236
-595
lines changed
 

‎.gitattributes

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
.py text eol=lf
6+
.rst text eol=lf
7+
.txt text eol=lf
8+
.yaml text eol=lf
9+
.toml text eol=lf
10+
.license text eol=lf
11+
.md text eol=lf

‎.pre-commit-config.yaml

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,21 @@
1-
# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
1+
# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
22
#
33
# SPDX-License-Identifier: Unlicense
44

55
repos:
6-
- repo: https://github.com/python/black
7-
rev: 23.3.0
8-
hooks:
9-
- id: black
10-
- repo: https://github.com/fsfe/reuse-tool
11-
rev: v1.1.2
12-
hooks:
13-
- id: reuse
146
- repo: https://github.com/pre-commit/pre-commit-hooks
15-
rev: v4.4.0
7+
rev: v4.5.0
168
hooks:
179
- id: check-yaml
1810
- id: end-of-file-fixer
1911
- id: trailing-whitespace
20-
- repo: https://github.com/pycqa/pylint
21-
rev: v3.3.1
12+
- repo: https://github.com/astral-sh/ruff-pre-commit
13+
rev: v0.3.4
2214
hooks:
23-
- id: pylint
24-
name: pylint (library code)
25-
types: [python]
26-
args:
27-
- --disable=consider-using-f-string
28-
exclude: "^(docs/|examples/|tests/|setup.py$)"
29-
- id: pylint
30-
name: pylint (example code)
31-
description: Run pylint rules on "examples/*.py" files
32-
types: [python]
33-
files: "^examples/"
34-
args:
35-
- --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code
36-
- id: pylint
37-
name: pylint (test code)
38-
description: Run pylint rules on "tests/*.py" files
39-
types: [python]
40-
files: "^tests/"
41-
args:
42-
- --disable=missing-docstring,consider-using-f-string,duplicate-code
15+
- id: ruff-format
16+
- id: ruff
17+
args: ["--fix"]
18+
- repo: https://github.com/fsfe/reuse-tool
19+
rev: v3.0.1
20+
hooks:
21+
- id: reuse

‎.pylintrc

Lines changed: 0 additions & 399 deletions
This file was deleted.

‎README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ Introduction
1717
:alt: Build Status
1818

1919

20-
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
21-
:target: https://github.com/psf/black
22-
:alt: Code Style: Black
20+
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
21+
:target: https://github.com/astral-sh/ruff
22+
:alt: Code Style: Ruff
2323

2424
Library for the Adafruit PyCamera
2525

‎adafruit_pycamera/__init__.py

Lines changed: 28 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# SPDX-License-Identifier: MIT
55
"""Library for the Adafruit PyCamera with OV5640 autofocus module"""
66

7-
# pylint: disable=too-many-lines
87
import gc
98
import os
109
import struct
@@ -19,10 +18,10 @@
1918
import adafruit_lis3dh
2019
import bitmaptools
2120
import board
22-
import displayio
23-
import fourwire
2421
import busdisplay
22+
import displayio
2523
import espcamera
24+
import fourwire
2625
import microcontroller
2726
import neopixel
2827
import pwmio
@@ -80,7 +79,7 @@
8079
_NVM_TIMELAPSE_SUBMODE = const(5)
8180

8281

83-
class PyCameraBase: # pylint: disable=too-many-instance-attributes,too-many-public-methods
82+
class PyCameraBase:
8483
"""Base class for PyCamera hardware
8584
8685
Wrapper class for the PyCamera hardware with lots of smarts
@@ -201,14 +200,14 @@ class PyCameraBase: # pylint: disable=too-many-instance-attributes,too-many-pub
201200
_INIT_SEQUENCE = (
202201
b"\x01\x80\x78" # _SWRESET and Delay 120ms
203202
b"\x11\x80\x05" # _SLPOUT and Delay 5ms
204-
b"\x3A\x01\x55" # _COLMOD
203+
b"\x3a\x01\x55" # _COLMOD
205204
b"\x21\x00" # _INVON Hack
206205
b"\x13\x00" # _NORON
207-
b"\x36\x01\xA0" # _MADCTL
206+
b"\x36\x01\xa0" # _MADCTL
208207
b"\x29\x80\x05" # _DISPON and Delay 5ms
209208
)
210209

211-
def __init__(self) -> None: # pylint: disable=too-many-statements
210+
def __init__(self) -> None:
212211
displayio.release_displays()
213212
self._i2c = board.I2C()
214213
self._spi = board.SPI()
@@ -273,7 +272,7 @@ def make_debounced_expander_pin(pin_no):
273272
pin.switch_to_input()
274273
return Debouncer(make_expander_input(pin_no))
275274

276-
self.up = make_debounced_expander_pin(_AW_UP) # pylint: disable=invalid-name
275+
self.up = make_debounced_expander_pin(_AW_UP)
277276
self.left = make_debounced_expander_pin(_AW_LEFT)
278277
self.right = make_debounced_expander_pin(_AW_RIGHT)
279278
self.down = make_debounced_expander_pin(_AW_DOWN)
@@ -313,19 +312,15 @@ def check_for_update_needed(self):
313312

314313
def make_camera_ui(self):
315314
"""Create displayio widgets for the standard camera UI"""
316-
self._sd_label = label.Label(
317-
terminalio.FONT, text="SD ??", color=0x0, x=170, y=10, scale=2
318-
)
315+
self._sd_label = label.Label(terminalio.FONT, text="SD ??", color=0x0, x=170, y=10, scale=2)
319316
self._effect_label = label.Label(
320317
terminalio.FONT, text="EFFECT", color=0xFFFFFF, x=4, y=10, scale=2
321318
)
322319
self._mode_label = label.Label(
323320
terminalio.FONT, text="MODE", color=0xFFFFFF, x=170, y=10, scale=2
324321
)
325322
self._topbar = displayio.Group()
326-
self._res_label = label.Label(
327-
terminalio.FONT, text="", color=0xFFFFFF, x=0, y=10, scale=2
328-
)
323+
self._res_label = label.Label(terminalio.FONT, text="", color=0xFFFFFF, x=0, y=10, scale=2)
329324
self._topbar.append(self._res_label)
330325
self._topbar.append(self._sd_label)
331326

@@ -365,9 +360,7 @@ def init_neopixel(self):
365360
neopix.deinit()
366361

367362
# front bezel neopixels
368-
self.pixels = neopixel.NeoPixel(
369-
board.A1, 8, brightness=0.1, pixel_order=neopixel.RGBW
370-
)
363+
self.pixels = neopixel.NeoPixel(board.A1, 8, brightness=0.1, pixel_order=neopixel.RGBW)
371364
self.pixels.fill(0)
372365

373366
def init_camera(self, init_autofocus=True) -> None:
@@ -470,9 +463,7 @@ def autofocus_init_from_bitstream(self, firmware: bytes):
470463
reg = offset + 0x8000
471464
arr[0] = reg >> 8
472465
arr[1] = reg & 0xFF
473-
arr[2 : 2 + num_firmware_bytes] = firmware[
474-
offset : offset + num_firmware_bytes
475-
]
466+
arr[2 : 2 + num_firmware_bytes] = firmware[offset : offset + num_firmware_bytes]
476467
i2c.write(arr, end=2 + num_firmware_bytes)
477468

478469
self.write_camera_list(self._finalize_firmware_load)
@@ -486,9 +477,7 @@ def autofocus_init_from_bitstream(self, firmware: bytes):
486477
def autofocus_init(self):
487478
"""Initialize the autofocus engine from ov5640_autofocus.bin"""
488479
if "/" in __file__:
489-
binfile = (
490-
__file__.rsplit("/", 1)[0].rsplit(".", 1)[0] + "/ov5640_autofocus.bin"
491-
)
480+
binfile = __file__.rsplit("/", 1)[0].rsplit(".", 1)[0] + "/ov5640_autofocus.bin"
492481
else:
493482
binfile = "ov5640_autofocus.bin"
494483
print(binfile)
@@ -499,7 +488,7 @@ def autofocus_status(self):
499488
"""Read the camera autofocus status register"""
500489
return self.read_camera_register(_OV5640_CMD_FW_STATUS)
501490

502-
def _send_autofocus_command(self, command, msg): # pylint: disable=unused-argument
491+
def _send_autofocus_command(self, command, msg):
503492
self.write_camera_register(_OV5640_CMD_ACK, 0x01) # clear command ack
504493
self.write_camera_register(_OV5640_CMD_MAIN, command) # send command
505494
for _ in range(100):
@@ -519,18 +508,14 @@ def autofocus(self) -> list[int]:
519508
return [False] * 5
520509
if not self._send_autofocus_command(_OV5640_CMD_TRIGGER_AUTOFOCUS, "autofocus"):
521510
return [False] * 5
522-
zone_focus = [
523-
self.read_camera_register(_OV5640_CMD_PARA0 + i) for i in range(5)
524-
]
511+
zone_focus = [self.read_camera_register(_OV5640_CMD_PARA0 + i) for i in range(5)]
525512
print(f"zones focused: {zone_focus}")
526513
return zone_focus
527514

528515
@property
529516
def autofocus_vcm_step(self):
530517
"""Get the voice coil motor step location"""
531-
if not self._send_autofocus_command(
532-
_OV5640_CMD_AF_GET_VCM_STEP, "get vcm step"
533-
):
518+
if not self._send_autofocus_command(_OV5640_CMD_AF_GET_VCM_STEP, "get vcm step"):
534519
return None
535520
return self.read_camera_register(_OV5640_CMD_PARA4)
536521

@@ -549,7 +534,7 @@ def select_setting(self, setting_name):
549534
self._effect_label.background_color = 0x0
550535
self._res_label.color = 0xFFFFFF
551536
self._res_label.background_color = 0x0
552-
if self.mode_text in ("GIF", "GBOY"):
537+
if self.mode_text in {"GIF", "GBOY"}:
553538
self._res_label.text = ""
554539
else:
555540
self._res_label.text = self.resolutions[self._resolution]
@@ -601,7 +586,7 @@ def mode(self, setting):
601586
self._mode_label.text = self.modes[setting]
602587
if self.modes[setting] == "STOP":
603588
self.stop_motion_frame = 0
604-
if self.modes[setting] in ("GIF", "GBOY"):
589+
if self.modes[setting] in {"GIF", "GBOY"}:
605590
self._res_label.text = ""
606591
else:
607592
self.resolution = self.resolution # kick it to reset the display
@@ -656,9 +641,7 @@ def timelapse_rate(self, setting):
656641
if self.timelapse_rates[setting] < 60:
657642
self.timelapse_rate_label.text = "%d S" % self.timelapse_rates[setting]
658643
else:
659-
self.timelapse_rate_label.text = "%d M" % (
660-
self.timelapse_rates[setting] / 60
661-
)
644+
self.timelapse_rate_label.text = "%d M" % (self.timelapse_rates[setting] / 60)
662645
microcontroller.nvm[_NVM_TIMELAPSE_RATE] = setting
663646
self.display.refresh()
664647

@@ -669,13 +652,9 @@ def timelapse_submode(self):
669652

670653
@timelapse_submode.setter
671654
def timelapse_submode(self, setting):
672-
setting = (setting + len(self.timelapse_submodes)) % len(
673-
self.timelapse_submodes
674-
)
655+
setting = (setting + len(self.timelapse_submodes)) % len(self.timelapse_submodes)
675656
self._timelapse_submode = setting
676-
self.timelapse_submode_label.text = self.timelapse_submodes[
677-
self._timelapse_submode
678-
]
657+
self.timelapse_submode_label.text = self.timelapse_submodes[self._timelapse_submode]
679658
microcontroller.nvm[_NVM_TIMELAPSE_SUBMODE] = setting
680659

681660
def init_display(self):
@@ -800,9 +779,7 @@ def keys_debounce(self):
800779

801780
def tone(self, frequency, duration=0.1):
802781
"""Play a tone on the internal speaker"""
803-
with pwmio.PWMOut(
804-
board.SPEAKER, frequency=int(frequency), variable_frequency=False
805-
) as pwm:
782+
with pwmio.PWMOut(board.SPEAKER, frequency=int(frequency), variable_frequency=False) as pwm:
806783
self.mute.value = True
807784
pwm.duty_cycle = 0x8000
808785
time.sleep(duration)
@@ -874,10 +851,9 @@ def overlay(self) -> str:
874851

875852
@overlay.setter
876853
def overlay(self, new_overlay_file: str) -> None:
877-
# pylint: disable=import-outside-toplevel
878-
from displayio import ColorConverter, Colorspace
879-
import ulab.numpy as np
880854
import adafruit_imageload
855+
import ulab.numpy as np
856+
from displayio import ColorConverter, Colorspace
881857

882858
if self.overlay_bmp is not None:
883859
self.overlay_bmp.deinit()
@@ -891,7 +867,6 @@ def overlay(self, new_overlay_file: str) -> None:
891867
del arr
892868

893869
def _init_jpeg_decoder(self):
894-
# pylint: disable=import-outside-toplevel
895870
from jpegio import JpegDecoder
896871

897872
"""
@@ -908,10 +883,7 @@ def blit_overlay_into_last_capture(self):
908883
in a separate but similarly named .bmp file on the SDCard.
909884
"""
910885
if self.overlay_bmp is None:
911-
raise ValueError(
912-
"Must set overlay before calling blit_overlay_into_last_capture"
913-
)
914-
# pylint: disable=import-outside-toplevel
886+
raise ValueError("Must set overlay before calling blit_overlay_into_last_capture")
915887
from adafruit_bitmapsaver import save_pixels
916888
from displayio import Bitmap, ColorConverter, Colorspace
917889

@@ -955,7 +927,7 @@ def last_saved_filename(self) -> str:
955927

956928
def continuous_capture_start(self):
957929
"""Switch the camera to continuous-capture mode"""
958-
pass # pylint: disable=unnecessary-pass
930+
pass
959931

960932
def capture_into_jpeg(self):
961933
"""Captures an image and returns it in JPEG format.
@@ -997,7 +969,6 @@ def blit(self, bitmap, x_offset=0, y_offset=32):
997969
The default preview capture is 240x176, leaving 32 pixel rows at the top and bottom
998970
for status information.
999971
"""
1000-
# pylint: disable=import-outside-toplevel
1001972
from displayio import Bitmap
1002973

1003974
if self.overlay_bmp is not None:
@@ -1025,9 +996,7 @@ def blit(self, bitmap, x_offset=0, y_offset=32):
1025996
self._display_bus.send(
1026997
42, struct.pack(">hh", 80 + x_offset, 80 + x_offset + bitmap.width - 1)
1027998
)
1028-
self._display_bus.send(
1029-
43, struct.pack(">hh", y_offset, y_offset + bitmap.height - 1)
1030-
)
999+
self._display_bus.send(43, struct.pack(">hh", y_offset, y_offset + bitmap.height - 1))
10311000
self._display_bus.send(44, bitmap)
10321001

10331002
@property
@@ -1066,8 +1035,7 @@ def get_camera_autosettings(self):
10661035
+ (self.read_camera_register(0x3502) >> 4)
10671036
)
10681037
white_balance = [
1069-
self.read_camera_register(x)
1070-
for x in (0x3400, 0x3401, 0x3402, 0x3403, 0x3404, 0x3405)
1038+
self.read_camera_register(x) for x in (0x3400, 0x3401, 0x3402, 0x3403, 0x3404, 0x3405)
10711039
]
10721040

10731041
settings = {
@@ -1147,6 +1115,6 @@ def __init__(self, init_autofocus=True):
11471115

11481116
try:
11491117
self.mount_sd_card()
1150-
except Exception as exc: # pylint: disable=broad-exception-caught
1118+
except Exception as exc:
11511119
# No SD card inserted, it's OK
11521120
print(exc)

‎adafruit_pycamera/imageprocessing.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ def ironbow(bitmap, mask=None):
8484
return bitmapfilter.false_color(bitmap, ironbow_palette, mask=mask)
8585

8686

87-
# pylint: disable=invalid-name
8887
def alphablend_maker(frac, nfrac=None):
8988
"""Create an alpha-blending function for a specific fractional value
9089

‎docs/api.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
.. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py)
55
.. use this format as the module name: "adafruit_foo.foo"
66
7+
API Reference
8+
#############
9+
710
.. automodule:: adafruit_pycamera
811
:members:
912
.. automodule:: adafruit_pycamera.imageprocessing

‎docs/conf.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
31
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
42
#
53
# SPDX-License-Identifier: MIT
@@ -75,9 +73,7 @@
7573
creation_year = "2023"
7674
current_year = str(datetime.datetime.now().year)
7775
year_duration = (
78-
current_year
79-
if current_year == creation_year
80-
else creation_year + " - " + current_year
76+
current_year if current_year == creation_year else creation_year + " - " + current_year
8177
)
8278
copyright = year_duration + " Jeff Epler for Adafruit Industries"
8379
author = "Jeff Epler for Adafruit Industries"

‎examples/basic_camera/code.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# SPDX-FileCopyrightText: Copyright (c) 2023 john park for Adafruit Industries
22
#
33
# SPDX-License-Identifier: MIT
4-
""" simple point-and-shoot camera example. No bells! Zero whistles! """
4+
"""simple point-and-shoot camera example. No bells! Zero whistles!"""
55

66
import time
7-
import adafruit_pycamera # pylint: disable=import-error
7+
8+
import adafruit_pycamera
89

910
pycam = adafruit_pycamera.PyCamera()
1011
pycam.mode = 0 # only mode 0 (JPEG) will work in this example
@@ -36,11 +37,11 @@
3637
pycam.display_message("snap", color=0x00DD00)
3738
pycam.capture_jpeg()
3839
pycam.live_preview_mode()
39-
except TypeError as exception:
40+
except TypeError:
4041
pycam.display_message("Failed", color=0xFF0000)
4142
time.sleep(0.5)
4243
pycam.live_preview_mode()
43-
except RuntimeError as exception:
44+
except RuntimeError:
4445
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
4546
time.sleep(0.5)
4647

‎examples/camera/boot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""Automatically create the /sd mount point at boot time"""
77

88
import os
9+
910
import storage
1011

1112
storage.remount("/", readonly=False)

‎examples/camera/code.py

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@
22
# SPDX-FileCopyrightText: 2023 Limor Fried for Adafruit Industries
33
#
44
# SPDX-License-Identifier: Unlicense
5-
import ssl
65
import os
6+
import ssl
77
import time
8-
import socketpool
9-
import adafruit_requests
10-
import rtc
8+
119
import adafruit_ntp
12-
import wifi
10+
import adafruit_requests
1311
import bitmaptools
1412
import displayio
1513
import gifio
14+
import rtc
15+
import socketpool
1616
import ulab.numpy as np
17+
import wifi
1718

1819
import adafruit_pycamera
1920

@@ -31,9 +32,7 @@
3132
PASSWORD = os.getenv("CIRCUITPY_WIFI_PASSWORD")
3233

3334
if SSID and PASSWORD:
34-
wifi.radio.connect(
35-
os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")
36-
)
35+
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
3736
if wifi.radio.connected:
3837
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}!")
3938
print("My IP address is", wifi.radio.ipv4_address)
@@ -46,9 +45,7 @@
4645
UTC_OFFSET = response_as_json["raw_offset"] + response_as_json["dst_offset"]
4746
print(f"UTC_OFFSET: {UTC_OFFSET}")
4847

49-
ntp = adafruit_ntp.NTP(
50-
pool, server="pool.ntp.org", tz_offset=UTC_OFFSET // 3600
51-
)
48+
ntp = adafruit_ntp.NTP(pool, server="pool.ntp.org", tz_offset=UTC_OFFSET // 3600)
5249

5350
print(f"ntp time: {ntp.datetime}")
5451
rtc.RTC().datetime = ntp.datetime
@@ -103,13 +100,9 @@
103100
pycam.timelapse_submode_label.text = pycam.timelapse_submode_label.text
104101

105102
# only in high power mode do we continuously preview
106-
if (timelapse_remaining is None) or (
107-
pycam.timelapse_submode_label.text == "HiPwr"
108-
):
103+
if (timelapse_remaining is None) or (pycam.timelapse_submode_label.text == "HiPwr"):
109104
pycam.blit(pycam.continuous_capture())
110-
if pycam.timelapse_submode_label.text == "LowPwr" and (
111-
timelapse_remaining is not None
112-
):
105+
if pycam.timelapse_submode_label.text == "LowPwr" and (timelapse_remaining is not None):
113106
pycam.display.brightness = 0.05
114107
else:
115108
pycam.display.brightness = 1
@@ -122,18 +115,16 @@
122115
try:
123116
pycam.display_message("Snap!", color=0x0000FF)
124117
pycam.capture_jpeg()
125-
except TypeError as e:
118+
except TypeError:
126119
pycam.display_message("Failed", color=0xFF0000)
127120
time.sleep(0.5)
128-
except RuntimeError as e:
121+
except RuntimeError:
129122
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
130123
time.sleep(0.5)
131124
pycam.live_preview_mode()
132125
pycam.display.refresh()
133126
pycam.blit(pycam.continuous_capture())
134-
timelapse_timestamp = (
135-
time.time() + pycam.timelapse_rates[pycam.timelapse_rate] + 1
136-
)
127+
timelapse_timestamp = time.time() + pycam.timelapse_rates[pycam.timelapse_rate] + 1
137128
else:
138129
pycam.blit(pycam.continuous_capture())
139130
# print("\t\t", capture_time, blit_time)
@@ -153,18 +144,18 @@
153144
try:
154145
pycam.display_message("Snap!", color=0x0000FF)
155146
pycam.capture_jpeg()
156-
except TypeError as e:
147+
except TypeError:
157148
pycam.display_message("Failed", color=0xFF0000)
158149
time.sleep(0.5)
159-
except RuntimeError as e:
150+
except RuntimeError:
160151
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
161152
time.sleep(0.5)
162153
pycam.live_preview_mode()
163154

164155
if pycam.mode_text == "GBOY":
165156
try:
166157
f = pycam.open_next_image("gif")
167-
except RuntimeError as e:
158+
except RuntimeError:
168159
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
169160
time.sleep(0.5)
170161
continue
@@ -181,13 +172,13 @@
181172
if pycam.mode_text == "GIF":
182173
try:
183174
f = pycam.open_next_image("gif")
184-
except RuntimeError as e:
175+
except RuntimeError:
185176
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
186177
time.sleep(0.5)
187178
continue
188179
i = 0
189180
ft = []
190-
pycam._mode_label.text = "RECORDING" # pylint: disable=protected-access
181+
pycam._mode_label.text = "RECORDING"
191182

192183
pycam.display.refresh()
193184
with gifio.GifWriter(
@@ -207,7 +198,7 @@
207198
ft.append(1 / (t1 - t0))
208199
print(end=".")
209200
t0 = t1
210-
pycam._mode_label.text = "GIF" # pylint: disable=protected-access
201+
pycam._mode_label.text = "GIF"
211202
print(f"\nfinal size {f.tell()} for {i} frames")
212203
print(f"average framerate {i / (t1 - t00)}fps")
213204
print(f"best {max(ft)} worst {min(ft)} std. deviation {np.std(ft)}")
@@ -220,11 +211,11 @@
220211
pycam.display_message("Snap!", color=0x0000FF)
221212
pycam.capture_jpeg()
222213
pycam.live_preview_mode()
223-
except TypeError as e:
214+
except TypeError:
224215
pycam.display_message("Failed", color=0xFF0000)
225216
time.sleep(0.5)
226217
pycam.live_preview_mode()
227-
except RuntimeError as e:
218+
except RuntimeError:
228219
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
229220
time.sleep(0.5)
230221

‎examples/filter/code.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,14 @@
1111
Otherwise, effects cycle every DISPLAY_INTERVAL milliseconds (default 2000 = 2 seconds)
1212
"""
1313

14+
import bitmapfilter
1415
import displayio
15-
from jpegio import JpegDecoder
1616
from adafruit_display_text.label import Label
17-
from adafruit_ticks import ticks_less, ticks_ms, ticks_add, ticks_diff
17+
from adafruit_ticks import ticks_add, ticks_diff, ticks_less, ticks_ms
1818
from font_free_mono_bold_24 import FONT
19-
import bitmapfilter
20-
21-
from adafruit_pycamera import imageprocessing
22-
from adafruit_pycamera import PyCameraBase
19+
from jpegio import JpegDecoder
2320

21+
from adafruit_pycamera import PyCameraBase, imageprocessing
2422

2523
blend_50_50 = bitmapfilter.blend_precompute(imageprocessing.alphablend_maker(0.5))
2624
screen = bitmapfilter.blend_precompute(imageprocessing.screen_func)
@@ -130,9 +128,7 @@ def sketch(b):
130128
("solarize", bitmapfilter.solarize),
131129
(
132130
"swap r/b",
133-
lambda b: bitmapfilter.mix(
134-
b, bitmapfilter.ChannelMixer(0, 0, 1, 0, 1, 0, 1, 0, 0)
135-
),
131+
lambda b: bitmapfilter.mix(b, bitmapfilter.ChannelMixer(0, 0, 1, 0, 1, 0, 1, 0, 0)),
136132
),
137133
]
138134

‎examples/overlay/code_select.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
# SPDX-FileCopyrightText: Copyright (c) 2024 Tim Cocks for Adafruit Industries
33
#
44
# SPDX-License-Identifier: MIT
5-
""" simple point-and-shoot camera example, with overly selecting using select button.
5+
"""simple point-and-shoot camera example, with overly selecting using select button.
66
77
Place all overlay files inside /sd/overlays/ directory.
88
"""
9+
910
import os
1011
import time
1112
import traceback
12-
import adafruit_pycamera # pylint: disable=import-error
13+
14+
import adafruit_pycamera
1315

1416
MODE_POSITION = 0
1517
MODE_SCALE = 1
@@ -57,19 +59,13 @@
5759

5860
if CURRENT_MODE == MODE_POSITION:
5961
if not pycam.down.value:
60-
pycam.overlay_position[1] += 1 * (
61-
int(pycam.down.current_duration / 0.3) + 1
62-
)
62+
pycam.overlay_position[1] += 1 * (int(pycam.down.current_duration / 0.3) + 1)
6363
if not pycam.up.value:
6464
pycam.overlay_position[1] -= 1 * (int(pycam.up.current_duration / 0.3) + 1)
6565
if not pycam.left.value:
66-
pycam.overlay_position[0] -= 1 * (
67-
int(pycam.left.current_duration / 0.3) + 1
68-
)
66+
pycam.overlay_position[0] -= 1 * (int(pycam.left.current_duration / 0.3) + 1)
6967
if not pycam.right.value:
70-
pycam.overlay_position[0] += 1 * (
71-
int(pycam.right.current_duration / 0.3) + 1
72-
)
68+
pycam.overlay_position[0] += 1 * (int(pycam.right.current_duration / 0.3) + 1)
7369
if CURRENT_MODE == MODE_SCALE:
7470
if pycam.down.fell:
7571
int_scale -= 10
@@ -98,7 +94,7 @@
9894
pycam.display_message("Failed", color=0xFF0000)
9995
time.sleep(0.5)
10096
pycam.live_preview_mode()
101-
except RuntimeError as exception:
97+
except RuntimeError:
10298
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
10399
time.sleep(0.5)
104100

‎examples/overlay/code_simple.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
# SPDX-FileCopyrightText: Copyright (c) 2024 Tim Cocks for Adafruit Industries
33
#
44
# SPDX-License-Identifier: MIT
5-
""" simple point-and-shoot camera example, with an overlay frame image. """
5+
"""simple point-and-shoot camera example, with an overlay frame image."""
66

77
import time
88
import traceback
9-
import adafruit_pycamera # pylint: disable=import-error
9+
10+
import adafruit_pycamera
1011

1112
pycam = adafruit_pycamera.PyCamera()
1213
pycam.mode = 0 # only mode 0 (JPEG) will work in this example
@@ -47,7 +48,7 @@
4748
pycam.display_message("Failed", color=0xFF0000)
4849
time.sleep(0.5)
4950
pycam.live_preview_mode()
50-
except RuntimeError as exception:
51+
except RuntimeError:
5152
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
5253
time.sleep(0.5)
5354

‎examples/qrio/code.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
from adafruit_pycamera import PyCamera
1515

1616
pycam = PyCamera()
17-
pycam._mode_label.text = "QR SCAN" # pylint: disable=protected-access
18-
pycam._res_label.text = "" # pylint: disable=protected-access
17+
pycam._mode_label.text = "QR SCAN"
18+
pycam._res_label.text = ""
1919
pycam.effect = 0
2020
pycam.camera.hmirror = False
2121
pycam.display.refresh()

‎examples/timestamp_filename/code.py

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
# SPDX-FileCopyrightText: Copyright (c) 2024 Tim Cocks for Adafruit Industries
22
#
33
# SPDX-License-Identifier: MIT
4-
""" simple point-and-shoot camera example. With NTP and internal RTC to
5-
add timestamp to photo filenames. Must install adafruit_ntp library!
6-
Example code assumes WIFI credentials are properly setup and web workflow
7-
enabled in settings.toml. If not, you'll need to add code to manually connect
8-
to your network."""
4+
"""simple point-and-shoot camera example. With NTP and internal RTC to
5+
add timestamp to photo filenames. Must install adafruit_ntp library!
6+
Example code assumes WIFI credentials are properly setup and web workflow
7+
enabled in settings.toml. If not, you'll need to add code to manually connect
8+
to your network."""
99

1010
import time
11-
import wifi
12-
import socketpool
13-
import rtc
11+
1412
import adafruit_ntp
15-
import adafruit_pycamera # pylint: disable=import-error
13+
import rtc
14+
import socketpool
15+
import wifi
16+
17+
import adafruit_pycamera
1618

1719
pool = socketpool.SocketPool(wifi.radio)
1820
ntp = adafruit_ntp.NTP(pool, tz_offset=0)
@@ -46,21 +48,14 @@
4648
pycam.tone(1600, 0.05)
4749
try:
4850
pycam.display_message("snap", color=0x00DD00)
49-
timestamp = "img_{}-{}-{}_{:02}-{:02}-{:02}_".format(
50-
time.localtime().tm_year,
51-
time.localtime().tm_mon,
52-
time.localtime().tm_mday,
53-
time.localtime().tm_hour,
54-
time.localtime().tm_min,
55-
time.localtime().tm_sec,
56-
)
51+
timestamp = f"img_{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}_{time.localtime().tm_hour:02}-{time.localtime().tm_min:02}-{time.localtime().tm_sec:02}_" # noqa: E501
5752
pycam.capture_jpeg(filename_prefix=timestamp)
5853
pycam.live_preview_mode()
59-
except TypeError as exception:
54+
except TypeError:
6055
pycam.display_message("Failed", color=0xFF0000)
6156
time.sleep(0.5)
6257
pycam.live_preview_mode()
63-
except RuntimeError as exception:
58+
except RuntimeError:
6459
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
6560
time.sleep(0.5)
6661

‎examples/viewer/code.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
Otherwise, images cycle every DISPLAY_INTERVAL milliseconds (default 8000 = 8 seconds)
1313
"""
1414

15-
import time
1615
import os
16+
import time
17+
1718
import displayio
19+
from adafruit_ticks import ticks_add, ticks_diff, ticks_less, ticks_ms
1820
from jpegio import JpegDecoder
19-
from adafruit_ticks import ticks_less, ticks_ms, ticks_add, ticks_diff
21+
2022
from adafruit_pycamera import PyCameraBase
2123

2224
DISPLAY_INTERVAL = 8000 # milliseconds
@@ -83,9 +85,7 @@ def mount_sd():
8385
pycam.display_message("SD Card\nFailed!", color=0xFF0000)
8486
time.sleep(0.5)
8587
all_images = [
86-
f"/sd/{filename}"
87-
for filename in os.listdir("/sd")
88-
if filename.lower().endswith(".jpg")
88+
f"/sd/{filename}" for filename in os.listdir("/sd") if filename.lower().endswith(".jpg")
8989
]
9090
pycam.display_message(f"Found {len(all_images)}\nimages", color=0xFFFFFF)
9191
time.sleep(0.5)
@@ -143,7 +143,7 @@ def main():
143143
image_counter = (image_counter + 1) % len(all_images)
144144
try:
145145
load_resized_image(bitmap, filename)
146-
except Exception as e: # pylint: disable=broad-exception-caught
146+
except Exception as e:
147147
pycam.display_message(f"Failed to read\n{filename}", color=0xFF0000)
148148
print(e)
149149
deadline = ticks_add(now, 500)

‎examples/web_camera/code.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ def body():
5151
request,
5252
body,
5353
headers={
54-
"Content-Type": "multipart/x-mixed-replace; boundary=%s"
55-
% BOUNDARY.decode("ascii")
54+
"Content-Type": "multipart/x-mixed-replace; boundary=%s" % BOUNDARY.decode("ascii")
5655
},
5756
)
5857

‎examples/web_settings_explorer/code.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,13 @@ def lcd(request: Request) -> Response:
6969
def take_jpeg(request: Request) -> Response:
7070
pycam.camera.reconfigure(
7171
pixel_format=espcamera.PixelFormat.JPEG,
72-
frame_size=pycam.resolution_to_frame_size[
73-
pycam._resolution # pylint: disable=protected-access
74-
],
72+
frame_size=pycam.resolution_to_frame_size[pycam._resolution],
7573
)
7674
try:
7775
jpeg = pycam.camera.take(1)
7876
if jpeg is not None:
7977
return Response(request, bytes(jpeg), content_type="image/jpeg")
80-
return Response(
81-
request, "", content_type="text/plain", status=INTERNAL_SERVER_ERROR_500
82-
)
78+
return Response(request, "", content_type="text/plain", status=INTERNAL_SERVER_ERROR_500)
8379
finally:
8480
pycam.live_preview_mode()
8581

@@ -109,13 +105,13 @@ def property_common(obj, request):
109105
try:
110106
current_value = getattr(obj, propname, None)
111107
return JSONResponse(request, current_value)
112-
except Exception as exc: # pylint: disable=broad-exception-caught
108+
except Exception as exc:
113109
return Response(request, {"error": str(exc)}, status=BAD_REQUEST_400)
114110
else:
115111
new_value = json.loads(value)
116112
setattr(obj, propname, new_value)
117113
return JSONResponse(request, {"status": "OK"})
118-
except Exception as exc: # pylint: disable=broad-exception-caught
114+
except Exception as exc:
119115
return JSONResponse(request, {"error": str(exc)}, status=BAD_REQUEST_400)
120116

121117

‎ruff.toml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
target-version = "py38"
6+
line-length = 100
7+
8+
[lint]
9+
preview = true
10+
select = ["I", "PL", "UP"]
11+
12+
extend-select = [
13+
"D419", # empty-docstring
14+
"E501", # line-too-long
15+
"W291", # trailing-whitespace
16+
"PLC0414", # useless-import-alias
17+
"PLC2401", # non-ascii-name
18+
"PLC2801", # unnecessary-dunder-call
19+
"PLC3002", # unnecessary-direct-lambda-call
20+
"E999", # syntax-error
21+
"PLE0101", # return-in-init
22+
"F706", # return-outside-function
23+
"F704", # yield-outside-function
24+
"PLE0116", # continue-in-finally
25+
"PLE0117", # nonlocal-without-binding
26+
"PLE0241", # duplicate-bases
27+
"PLE0302", # unexpected-special-method-signature
28+
"PLE0604", # invalid-all-object
29+
"PLE0605", # invalid-all-format
30+
"PLE0643", # potential-index-error
31+
"PLE0704", # misplaced-bare-raise
32+
"PLE1141", # dict-iter-missing-items
33+
"PLE1142", # await-outside-async
34+
"PLE1205", # logging-too-many-args
35+
"PLE1206", # logging-too-few-args
36+
"PLE1307", # bad-string-format-type
37+
"PLE1310", # bad-str-strip-call
38+
"PLE1507", # invalid-envvar-value
39+
"PLE2502", # bidirectional-unicode
40+
"PLE2510", # invalid-character-backspace
41+
"PLE2512", # invalid-character-sub
42+
"PLE2513", # invalid-character-esc
43+
"PLE2514", # invalid-character-nul
44+
"PLE2515", # invalid-character-zero-width-space
45+
"PLR0124", # comparison-with-itself
46+
"PLR0202", # no-classmethod-decorator
47+
"PLR0203", # no-staticmethod-decorator
48+
"UP004", # useless-object-inheritance
49+
"PLR0206", # property-with-parameters
50+
"PLR0904", # too-many-public-methods
51+
"PLR0911", # too-many-return-statements
52+
"PLR0912", # too-many-branches
53+
"PLR0913", # too-many-arguments
54+
"PLR0914", # too-many-locals
55+
"PLR0915", # too-many-statements
56+
"PLR0916", # too-many-boolean-expressions
57+
"PLR1702", # too-many-nested-blocks
58+
"PLR1704", # redefined-argument-from-local
59+
"PLR1711", # useless-return
60+
"C416", # unnecessary-comprehension
61+
"PLR1733", # unnecessary-dict-index-lookup
62+
"PLR1736", # unnecessary-list-index-lookup
63+
64+
# ruff reports this rule is unstable
65+
#"PLR6301", # no-self-use
66+
67+
"PLW0108", # unnecessary-lambda
68+
"PLW0120", # useless-else-on-loop
69+
"PLW0127", # self-assigning-variable
70+
"PLW0129", # assert-on-string-literal
71+
"B033", # duplicate-value
72+
"PLW0131", # named-expr-without-context
73+
"PLW0245", # super-without-brackets
74+
"PLW0406", # import-self
75+
"PLW0602", # global-variable-not-assigned
76+
"PLW0603", # global-statement
77+
"PLW0604", # global-at-module-level
78+
79+
# fails on the try: import typing used by libraries
80+
#"F401", # unused-import
81+
82+
"F841", # unused-variable
83+
"E722", # bare-except
84+
"PLW0711", # binary-op-exception
85+
"PLW1501", # bad-open-mode
86+
"PLW1508", # invalid-envvar-default
87+
"PLW1509", # subprocess-popen-preexec-fn
88+
"PLW2101", # useless-with-lock
89+
"PLW3301", # nested-min-max
90+
]
91+
92+
ignore = [
93+
"PLR2004", # magic-value-comparison
94+
"UP030", # format literals
95+
"PLW1514", # unspecified-encoding
96+
"PLR0913", # too-many-arguments
97+
"PLR0915", # too-many-statements
98+
"PLR0917", # too-many-positional-arguments
99+
"PLR0904", # too-many-public-methods
100+
"PLR0912", # too-many-branches
101+
"PLR0916", # too-many-boolean-expressions
102+
"PLR6301", # could-be-static no-self-use
103+
"PLC0415", # import outside toplevel
104+
"PLC2701", # private import
105+
]
106+
107+
[format]
108+
line-ending = "lf"

0 commit comments

Comments
 (0)
Please sign in to comment.