scietex.hal.spi
SPI transport backends shared by the scietex.hal.* device distributions.
A transport is the narrow seam between a device driver and the bus. Devices
send whole frames through transfer() and release the bus with close(), so
the same driver works over spidev, over gpiozero's hardware SPI, or over a
scripted fake in tests. The package ships no device code and has no runtime
dependencies: the optional backends are imported only when they are used.
The protocol
class SpiTransport(Protocol):
def transfer(self, tx: Sequence[int]) -> list[int]: ...
def close(self) -> None: ...
transfer(tx)sends one frame of words in0..255and returns the received words in the same order.close()releases the bus handle; repeated calls have no effect. If the underlying close fails, the transport stays open andclose()can be retried.closedisTrueonceclose()has run. For a transport that wraps a caller-supplied handle, it reports that the transport itself is closed, not that the shared bus was closed.
Any object with callable transfer and close methods is accepted. Use
is_spi_transport(obj) for the check: unlike isinstance(obj, SpiTransport),
it rejects class objects. Use SpiTransport for typing only.
Failures raise TransportError, which subclasses OSError so callers that
already handle spidev or gpiozero I/O errors keep working. A transaction
attempted after close raises TransportClosed, a TransportError subclass.
Backends
| Transport | Install | Notes |
|---|---|---|
SpiDevTransport |
pip install 'scietex.hal.spi[spi]' |
Default. Opens /dev/spidev<bus>.<device> through spidev, Linux only. |
GpiozeroSpiTransport |
pip install 'scietex.hal.spi[gpiozero]' |
Wraps a gpiozero hardware SPI object. Resolved lazily as scietex.hal.spi.GpiozeroSpiTransport. |
FakeSpiTransport |
none | In-memory backend with scripted responses, for tests without hardware. |
from scietex.hal.spi import SpiDevTransport
transport = SpiDevTransport(bus=0, device=0, max_speed_hz=500_000)
transport.transfer([0x00, 43])
transport.close()
SpiDevTransport transfers with xfer2, which keeps chip select asserted for
the whole frame; xfer would deassert it between 8-bit words.
GpiozeroSpiTransport builds a private shared gpiozero SPIDevice by default,
or wraps one supplied with spi=. On a Raspberry Pi it also patches gpiozero so
two hardware-SPI devices can share one port when they use different chip-select
lines (fix_gpiozero_dual_cs_spi, also exported for callers that build their
own gpiozero devices). Without the RPi pin backend the patch is a no-op.
A bare install ships no hardware backend; constructing one raises ImportError
naming the extra to install.
Default selection
build_default_transport maps the legacy device keywords onto a backend:
| Keyword | SpiDevTransport |
GpiozeroSpiTransport |
|---|---|---|
port |
bus |
port |
device |
device |
device |
clock_pin, mosi_pin, miso_pin, select_pin |
selects the gpiozero backend | forwarded as-is |
from scietex.hal.spi import build_default_transport
build_default_transport(port=0, device=1) # SpiDevTransport(bus=0, device=1)
build_default_transport(clock_pin=11, mosi_pin=10) # GpiozeroSpiTransport(...)
Any pin keyword selects the gpiozero backend and requires the gpiozero
extra; without pin keywords the spidev backend is built with port or 0 and
device or 0. port and device are accepted by both backends and are simply
forwarded.
The selector takes backend keywords only. Conflict rejection — passing backend
keywords together with transport= or spi= — is the responsibility of each
device constructor, which owns that argument surface; the selector itself raises
TypeError when given a transport= keyword.
Ownership
Create one transport per device; all channels of a device share it. The device's
close() delegates to its transport.
SpiDevTransportalways owns and closes its spidev handle.GpiozeroSpiTransportcloses only a handle it built. When it wraps a caller-suppliedspi=object,close()marks the transport closed but leaves the shared bus open for its other users; the supplied handle's owner must outlive the wrapper and close it. Once that owner closes the handle, transfers through the wrapper raiseTransportClosed.FakeSpiTransportonly flips itsclosedflag.
Linux permissions
SpiDevTransport needs the kernel SPI device node and permission to open it.
Enable kernel SPI first, for example with dtparam=spi=on in
/boot/firmware/config.txt on current Raspberry Pi OS (the older path is
/boot/config.txt).
If the node exists but opening fails, add a udev rule. The development setup for
these packages uses the gpio group; adjust the group to match your system::
SUBSYSTEM=="spidev", GROUP="gpio", MODE="0660"
Install the rule under /etc/udev/rules.d/, reload the rules, and reconnect the
device. The user running the process must be a member of the group named in the
rule; on Fedora setups that group is gpio, because no spi group exists.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Metadata
Release files for scietex.hal.spi 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| scietex_hal_spi-0.1.0.tar.gz | 24.4 kB | With provenance | Details for scietex_hal_spi-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| scietex_hal_spi-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for scietex_hal_spi-0.1.0-py3-none-any.whl |
Total release size: 40.4 kB
Release files / scietex_hal_spi-0.1.0.tar.gz
| Download URL | scietex_hal_spi-0.1.0.tar.gz |
|---|---|
| Size | 24.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f1aa28f22c1d68d46eeddf6105ec3ceb486100c90d6564a1fe4462d1f7920267
|
|
BLAKE2b-256 checksum How to use checksums |
41687d1ef80b233c8d46deaa27093d4aa30327a9bba125076985ec8901546632
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logRelease files / scietex_hal_spi-0.1.0-py3-none-any.whl
| Download URL | scietex_hal_spi-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0350840d53bb21c0b18554a64f19eb914df3442619cb55a38f019e6b5d4db032
|
|
BLAKE2b-256 checksum How to use checksums |
5c0d61f4d24de7ce82b175a51004e4450258a3bc1899b307bc5ec6ba9cdc4d8f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logSecurity for scietex.hal.spi 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for scietex_hal_spi-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.