Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardise on one approach to numeric parsing, drop Long support from Python 2.x #98

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 53 additions & 120 deletions spidev_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,13 @@
#define XFER3_MAX_BLOCK_SIZE 65535


#if PY_MAJOR_VERSION < 3
#define PyLong_AS_LONG(val) PyInt_AS_LONG(val)
#define PyLong_AsLong(val) PyInt_AsLong(val)
#endif

// Macros needed for Python 3
#ifndef PyInt_Check
#define PyInt_Check PyLong_Check
#define PyInt_Check PyLong_Check
#define PyInt_FromLong PyLong_FromLong
#define PyInt_AsLong PyLong_AsLong
#define PyInt_Type PyLong_Type
#define PyInt_AsLong PyLong_AsLong
#define PyInt_Type PyLong_Type
#define PyInt_AS_LONG PyLong_AS_LONG
#endif

// Maximum block size for xfer3
Expand Down Expand Up @@ -197,19 +193,12 @@ SpiDev_writebytes(SpiDevObject *self, PyObject *args)

for (ii = 0; ii < len; ii++) {
PyObject *val = PySequence_Fast_GET_ITEM(seq, ii);
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
buf[ii] = (__u8)PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
buf[ii] = (__u8)PyLong_AS_LONG(val);
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
return NULL;
}
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
return NULL;
}
}

Expand Down Expand Up @@ -323,19 +312,12 @@ SpiDev_writebytes2_seq_internal(SpiDevObject *self, PyObject *seq, Py_ssize_t le

for (ii = 0; ii < block_size; ii++, jj++) {
PyObject *val = PySequence_Fast_GET_ITEM(seq, jj);
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
buf[ii] = (__u8)PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
buf[ii] = (__u8)PyLong_AS_LONG(val);
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
return NULL;
}
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
return NULL;
}
}

Expand Down Expand Up @@ -498,22 +480,15 @@ SpiDev_xfer(SpiDevObject *self, PyObject *args)

for (ii = 0; ii < len; ii++) {
PyObject *val = PySequence_Fast_GET_ITEM(seq, ii);
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
txbuf[ii] = (__u8)PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
txbuf[ii] = (__u8)PyLong_AS_LONG(val);
} else {
snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(xferptr);
free(txbuf);
free(rxbuf);
return NULL;
}
} else {
snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(xferptr);
free(txbuf);
free(rxbuf);
return NULL;
}
xferptr[ii].tx_buf = (unsigned long)&txbuf[ii];
xferptr[ii].rx_buf = (unsigned long)&rxbuf[ii];
Expand All @@ -540,21 +515,14 @@ SpiDev_xfer(SpiDevObject *self, PyObject *args)
#else
for (ii = 0; ii < len; ii++) {
PyObject *val = PySequence_Fast_GET_ITEM(seq, ii);
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
txbuf[ii] = (__u8)PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
txbuf[ii] = (__u8)PyLong_AS_LONG(val);
} else {
snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(txbuf);
free(rxbuf);
return NULL;
}
} else {
snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(txbuf);
free(rxbuf);
return NULL;
}
}

Expand Down Expand Up @@ -656,21 +624,14 @@ SpiDev_xfer2(SpiDevObject *self, PyObject *args)

for (ii = 0; ii < len; ii++) {
PyObject *val = PySequence_Fast_GET_ITEM(seq, ii);
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
txbuf[ii] = (__u8)PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
txbuf[ii] = (__u8)PyLong_AS_LONG(val);
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(txbuf);
free(rxbuf);
return NULL;
}
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(txbuf);
free(rxbuf);
return NULL;
}
}

Expand Down Expand Up @@ -804,23 +765,16 @@ SpiDev_xfer3(SpiDevObject *self, PyObject *args)

for (ii = 0, jj = block_start; jj < len && ii < bufsize; ii++, jj++) {
PyObject *val = PySequence_Fast_GET_ITEM(seq, jj);
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
txbuf[ii] = (__u8)PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
txbuf[ii] = (__u8)PyLong_AS_LONG(val);
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(txbuf);
free(rxbuf);
Py_DECREF(rx_tuple);
Py_DECREF(seq);
return NULL;
}
} else {
snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val);
PyErr_SetString(PyExc_TypeError, wrmsg_text);
free(txbuf);
free(rxbuf);
Py_DECREF(rx_tuple);
Py_DECREF(seq);
return NULL;
}
}

Expand All @@ -846,7 +800,7 @@ SpiDev_xfer3(SpiDevObject *self, PyObject *args)
return NULL;
}
for (ii = 0, jj = block_start; ii < block_size; ii++, jj++) {
PyObject *val = PyLong_FromLong((long)rxbuf[ii]);
PyObject *val = PyInt_FromLong((unsigned long)rxbuf[ii]);
PyTuple_SetItem(rx_tuple, jj, val); // Steals reference, no need to Py_DECREF(val)
}

Expand Down Expand Up @@ -989,19 +943,12 @@ SpiDev_set_mode(SpiDevObject *self, PyObject *val, void *closure)
"Cannot delete attribute");
return -1;
}
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
mode = PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
mode = PyLong_AS_LONG(val);
} else {
PyErr_SetString(PyExc_TypeError,
"The mode attribute must be an integer");
return -1;
}
} else {
PyErr_SetString(PyExc_TypeError,
"The mode attribute must be an integer");
return -1;
}


Expand Down Expand Up @@ -1186,22 +1133,15 @@ SpiDev_set_bits_per_word(SpiDevObject *self, PyObject *val, void *closure)
"Cannot delete attribute");
return -1;
}
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
bits = PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
bits = PyLong_AS_LONG(val);
} else {
PyErr_SetString(PyExc_TypeError,
"The bits_per_word attribute must be an integer");
return -1;
}
} else {
PyErr_SetString(PyExc_TypeError,
"The bits_per_word attribute must be an integer");
return -1;
}

if (bits < 8 || bits > 32) {
if (bits < 8 || bits > 32) {
PyErr_SetString(PyExc_TypeError,
"invalid bits_per_word (8 to 32)");
return -1;
Expand Down Expand Up @@ -1235,19 +1175,12 @@ SpiDev_set_max_speed_hz(SpiDevObject *self, PyObject *val, void *closure)
"Cannot delete attribute");
return -1;
}
#if PY_MAJOR_VERSION < 3
if (PyInt_Check(val)) {
max_speed_hz = PyInt_AS_LONG(val);
} else
#endif
{
if (PyLong_Check(val)) {
max_speed_hz = PyLong_AS_LONG(val);
} else {
PyErr_SetString(PyExc_TypeError,
"The max_speed_hz attribute must be an integer");
return -1;
}
} else {
PyErr_SetString(PyExc_TypeError,
"The max_speed_hz attribute must be an integer");
return -1;
}

if (self->max_speed_hz != max_speed_hz) {
Expand Down
15 changes: 15 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Python Spidev Tests
===================

These tests are intended to validate the behaviour of Spidev's functions and properties.

They have been run in Python 2.7 and 3 on a Raspberry Pi 4.

A short jumper wire is required between pins BCM9 (MISO) and BCM10 (MOSI) in order for loopback tests to pass, you must also enable SPI.

Tests depend upon pytest and can be run against spidev in a virtual environment with:

```
python setup.py develop
python -m py.test -v -r wsx
```
12 changes: 12 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import sys
import pytest

@pytest.fixture
def spidev():
import spidev
dev = spidev.SpiDev(0, 0)
# Slow down SPI bus to ensure a stable result for loopback testing
dev.max_speed_hz = 100000
yield dev
del sys.modules["spidev"]

28 changes: 28 additions & 0 deletions tests/test_spidev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

def test_spidev_set_mode(spidev):
spidev.mode = 0
assert spidev.mode == 0
spidev.mode = 1
assert spidev.mode == 1

def test_spidev_bits_per_word_raises_typeerror(spidev):
with pytest.raises(TypeError):
spidev.bits_per_word = "1"
try:
bits = long(8)
with pytest.raises(TypeError):
spidev.bits_per_word = bits
except NameError:
pass

def test_spidev_mode_raises_typeerror(spidev):
with pytest.raises(TypeError):
spidev.mode = "1"
try:
mode = long(1)
with pytest.raises(TypeError):
spidev.mode = mode
except NameError:
pass

27 changes: 27 additions & 0 deletions tests/test_xfer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest

def test_xfer_loopback(spidev):
result = spidev.xfer([n for n in range(255)])
assert result == [n for n in range(255)]

def test_xfer_empty_list_raises_type_error(spidev):
data = []
with pytest.raises(TypeError):
spidev.xfer(data)

def test_xfer_oversized_list_raises_overflow_error(spidev):
data = [0 for _ in range(4097)]
with pytest.raises(OverflowError):
spidev.xfer(data)

def test_xfer_invalid_list_entry_raises_type_error(spidev):
data = ["1"]
with pytest.raises(TypeError):
spidev.xfer(data)
try:
data = [long(1)]
with pytest.raises(TypeError):
spidev.xfer(data)
except NameError:
pass

27 changes: 27 additions & 0 deletions tests/test_xfer2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest

def test_xfer2_loopback(spidev):
result = spidev.xfer2([n for n in range(255)])
assert result == [n for n in range(255)]

def test_xfer2_empty_list_raises_type_error(spidev):
data = []
with pytest.raises(TypeError):
spidev.xfer2(data)

def test_xfer2_oversized_list_raises_overflow_error(spidev):
data = [0 for _ in range(4097)]
with pytest.raises(OverflowError):
spidev.xfer2(data)

def test_xfer2_invalid_list_entry_raises_type_error(spidev):
data = ["1"]
with pytest.raises(TypeError):
spidev.xfer2(data)
try:
data = [long(1)]
with pytest.raises(TypeError):
spidev.xfer2(data)
except NameError:
pass

Loading