Skip to content

Commit d4f814c

Browse files
authored
Add CI workflow for Python testing with Tox (#95)
* Add CI workflow for Python testing with Tox * Remove travis config * Keep on truckin' * Revert * tweaks
1 parent 6f06524 commit d4f814c

File tree

13 files changed

+349
-234
lines changed

13 files changed

+349
-234
lines changed

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
8+
- package-ecosystem: "pip"
9+
directory: "/"
10+
schedule:
11+
interval: "weekly"

.github/workflows/ci.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
python-version: [3.11, 3.12, 3.13, 3.14]
15+
include:
16+
- python-version: 3.11
17+
env: TOXENV=qa
18+
19+
env:
20+
TOX_PARALLEL_NO_SPINNER: 1
21+
22+
steps:
23+
- name: Check out code
24+
uses: actions/checkout@v4
25+
26+
- name: Set up Python
27+
uses: actions/setup-python@v5
28+
with:
29+
python-version: ${{ matrix.python-version }}
30+
31+
- name: Install dependencies
32+
run: |
33+
python -m pip install --upgrade pip
34+
pip install tox coveralls setuptools
35+
36+
- name: Run tests
37+
run: tox -vv
38+
env:
39+
TOXENV: ${{ matrix.env.TOXENV || format('py{0}', matrix.python-version) }}
40+
41+
- name: Upload coverage to Coveralls (only for 3.11)
42+
if: matrix.python-version == '3.11' && success()
43+
run: coveralls
44+
env:
45+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.travis.yml

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

OPi/GPIO.py

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -395,11 +395,11 @@ def my_callback_two(channel):
395395
import warnings
396396

397397
from OPi.constants import IN, OUT
398-
from OPi.constants import LOW, HIGH # noqa: F401
399-
from OPi.constants import NONE, RISING, FALLING, BOTH # noqa: F401
398+
from OPi.constants import LOW, HIGH # noqa: F401
399+
from OPi.constants import NONE, RISING, FALLING, BOTH # noqa: F401
400400
from OPi.constants import BCM, BOARD, SUNXI, CUSTOM
401-
from OPi.constants import PUD_UP, PUD_DOWN, PUD_OFF # noqa: F401
402-
from OPi.constants import RED, GREEN # LEDs
401+
from OPi.constants import PUD_UP, PUD_DOWN, PUD_OFF # noqa: F401
402+
from OPi.constants import RED, GREEN # noqa: F401
403403
from OPi.pin_mappings import get_gpio_pin, set_custom_pin_mappings
404404
from OPi import event, sysfs
405405

@@ -436,7 +436,7 @@ def setmode(mode):
436436
:py:attr:`GPIO.SUNXI`, or a `dict` or `object` representing a custom
437437
pin mapping.
438438
"""
439-
if hasattr(mode, '__getitem__'):
439+
if hasattr(mode, "__getitem__"):
440440
set_custom_pin_mappings(mode)
441441
mode = CUSTOM
442442

@@ -499,7 +499,10 @@ def setup(channel, direction, initial=None, pull_up_down=None):
499499

500500
if pull_up_down is not None:
501501
if _gpio_warnings:
502-
warnings.warn("Pull up/down setting are not (yet) fully supported, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.", stacklevel=2)
502+
warnings.warn(
503+
"Pull up/down setting are not (yet) fully supported, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.",
504+
stacklevel=2,
505+
)
503506

504507
if isinstance(channel, list):
505508
for ch in channel:
@@ -511,9 +514,14 @@ def setup(channel, direction, initial=None, pull_up_down=None):
511514
try:
512515
sysfs.export(pin)
513516
except (OSError, IOError) as e:
514-
if e.errno == 16: # Device or resource busy
517+
if e.errno == 16: # Device or resource busy
515518
if _gpio_warnings:
516-
warnings.warn("Channel {0} is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.".format(channel), stacklevel=2)
519+
warnings.warn(
520+
"Channel {0} is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.".format(
521+
channel
522+
),
523+
stacklevel=2,
524+
)
517525
sysfs.unexport(pin)
518526
sysfs.export(pin)
519527
else:
@@ -565,6 +573,7 @@ def output(channel, state):
565573
pin = get_gpio_pin(_mode, channel)
566574
return sysfs.output(pin, state)
567575

576+
568577
def setled(led, state):
569578
"""
570579
Set the state of a onboard LEDs.
@@ -583,11 +592,12 @@ def setled(led, state):
583592
GPIO.led(leds_list, (GPIO.HIGH, GPIO.LOW)) # sets first LED ON and second LED OFF
584593
"""
585594
if isinstance(led, list):
586-
for l in led:
587-
setled(l, state)
595+
for led_item in led:
596+
setled(led_item, state)
588597
else:
589598
return sysfs.setled(led, state)
590599

600+
591601
def wait_for_edge(channel, trigger, timeout=-1):
592602
"""
593603
This function is designed to block execution of your program until an edge
@@ -655,7 +665,10 @@ def add_event_detect(channel, trigger, callback=None, bouncetime=None):
655665

656666
if bouncetime is not None:
657667
if _gpio_warnings:
658-
warnings.warn("bouncetime is not (yet) fully supported, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.", stacklevel=2)
668+
warnings.warn(
669+
"bouncetime is not (yet) fully supported, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.",
670+
stacklevel=2,
671+
)
659672

660673
pin = get_gpio_pin(_mode, channel)
661674
event.add_edge_detect(pin, trigger, __wrap(callback, channel))
@@ -682,7 +695,10 @@ def add_event_callback(channel, callback, bouncetime=None):
682695

683696
if bouncetime is not None:
684697
if _gpio_warnings:
685-
warnings.warn("bouncetime is not (yet) fully supported, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.", stacklevel=2)
698+
warnings.warn(
699+
"bouncetime is not (yet) fully supported, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.",
700+
stacklevel=2,
701+
)
686702

687703
pin = get_gpio_pin(_mode, channel)
688704
event.add_edge_callback(pin, __wrap(callback, channel))
@@ -768,8 +784,9 @@ class PWM:
768784
# 2. find way to check _exports against _exports_pwm to make sure there is no overlap.
769785
# 3. Create map of pwm pins to various boards.
770786

771-
def __init__(self, chip, pin, frequency, duty_cycle_percent, invert_polarity=False): # (pwm pin, frequency in KHz)
772-
787+
def __init__(
788+
self, chip, pin, frequency, duty_cycle_percent, invert_polarity=False
789+
): # (pwm pin, frequency in KHz)
773790
"""
774791
Setup the PWM object to control.
775792
@@ -791,34 +808,47 @@ def __init__(self, chip, pin, frequency, duty_cycle_percent, invert_polarity=Fal
791808
try:
792809
sysfs.PWM_Export(chip, pin) # creates the pwm sysfs object
793810
except (OSError, IOError) as e:
794-
if e.errno == 16: # Device or resource busy
795-
warnings.warn("Pin {0} is already in use, continuing anyway.".format(pin), stacklevel=2)
811+
if e.errno == 16: # Device or resource busy
812+
warnings.warn(
813+
"Pin {0} is already in use, continuing anyway.".format(pin),
814+
stacklevel=2,
815+
)
796816
sysfs.PWM_Unexport(chip, pin)
797817
sysfs.PWM_Export(chip, pin)
798818
else:
799819
raise e
800820

801821
# invert polarity if needed
802822
if invert_polarity is True:
803-
sysfs.PWM_Polarity(chip, pin, invert=True) # invert pwm i.e the duty cycle tells you how long the cycle is off
823+
sysfs.PWM_Polarity(
824+
chip, pin, invert=True
825+
) # invert pwm i.e the duty cycle tells you how long the cycle is off
804826
else:
805-
sysfs.PWM_Polarity(chip, pin, invert=False) # don't invert the pwm signal. This is the normal way its used.
827+
sysfs.PWM_Polarity(
828+
chip, pin, invert=False
829+
) # don't invert the pwm signal. This is the normal way its used.
806830

807831
# enable pwm
808832
sysfs.PWM_Enable(chip, pin)
809833
sysfs.PWM_Frequency(chip, pin, frequency)
810834

811-
def start_pwm(self): # turn on pwm by setting the duty cycle to what the user specified
835+
def start_pwm(
836+
self,
837+
): # turn on pwm by setting the duty cycle to what the user specified
812838
"""
813839
Start PWM Signal.
814840
"""
815-
return sysfs.PWM_Duty_Cycle_Percent(self.chip, self.pin, self.duty_cycle_percent) # duty cycle controls the on-off
841+
return sysfs.PWM_Duty_Cycle_Percent(
842+
self.chip, self.pin, self.duty_cycle_percent
843+
) # duty cycle controls the on-off
816844

817845
def stop_pwm(self): # turn on pwm by setting the duty cycle to 0
818846
"""
819847
Stop PWM Signal.
820848
"""
821-
return sysfs.PWM_Duty_Cycle_Percent(self.chip, self.pin, 0) # duty cycle at 0 is the equivilant of off
849+
return sysfs.PWM_Duty_Cycle_Percent(
850+
self.chip, self.pin, 0
851+
) # duty cycle at 0 is the equivilant of off
822852

823853
def change_frequency(self, new_frequency):
824854
# Order of operations:
@@ -842,7 +872,7 @@ def change_frequency(self, new_frequency):
842872

843873
old_pwm_period = int(round((1 / self.frequency) * 1e9, 0))
844874

845-
if (pwm_period > old_pwm_period): # if increasing
875+
if pwm_period > old_pwm_period: # if increasing
846876
sysfs.PWM_Period(self.chip, self.pin, pwm_period) # update the pwm period
847877
sysfs.PWM_Duty_Cycle(self.chip, self.pin, duty_cycle) # update duty cycle
848878

@@ -859,18 +889,24 @@ def duty_cycle(self, duty_cycle_percent): # in percentage (0-100)
859889
:param duty_cycle_percent: the new PWM duty cycle as a percentage.
860890
"""
861891

862-
if (0 <= duty_cycle_percent <= 100):
892+
if 0 <= duty_cycle_percent <= 100:
863893
self.duty_cycle_percent = duty_cycle_percent
864-
return sysfs.PWM_Duty_Cycle_Percent(self.chip, self.pin, self.duty_cycle_percent)
894+
return sysfs.PWM_Duty_Cycle_Percent(
895+
self.chip, self.pin, self.duty_cycle_percent
896+
)
865897
else:
866-
raise Exception("Duty cycle must br between 0 and 100. Current value: {0} is out of bounds".format(duty_cycle_percent))
898+
raise Exception(
899+
"Duty cycle must br between 0 and 100. Current value: {0} is out of bounds".format(
900+
duty_cycle_percent
901+
)
902+
)
867903

868904
def pwm_polarity(self): # invert the polarity of the pwm
869905
"""
870906
Invert the signal.
871907
"""
872908
sysfs.PWM_Disable(self.chip, self.pin)
873-
sysfs.PWM_Polarity(self.chip, self.pin, invert=not(self.invert_polarity))
909+
sysfs.PWM_Polarity(self.chip, self.pin, invert=not (self.invert_polarity))
874910
sysfs.PWM_Enable(self.chip, self.pin)
875911

876912
def pwm_close(self):

OPi/event.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ def blocking_wait_for_edge(pin, trigger, timeout=-1):
8989
assert trigger in [RISING, FALLING, BOTH]
9090

9191
if pin in _threads:
92-
raise RuntimeError("Conflicting edge detection events already exist for this GPIO channel")
92+
raise RuntimeError(
93+
"Conflicting edge detection events already exist for this GPIO channel"
94+
)
9395

9496
try:
9597
sysfs.edge(pin, trigger)
@@ -133,7 +135,9 @@ def add_edge_detect(pin, trigger, callback=None):
133135
assert trigger in [RISING, FALLING, BOTH]
134136

135137
if pin in _threads:
136-
raise RuntimeError("Conflicting edge detection already enabled for this GPIO channel")
138+
raise RuntimeError(
139+
"Conflicting edge detection already enabled for this GPIO channel"
140+
)
137141

138142
_threads[pin] = _worker(pin, trigger, callback)
139143
_threads[pin].start()

0 commit comments

Comments
 (0)