diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..0bc5b768
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,28 @@
+name: CI Pipeline
+
+on:
+ push:
+ branches: 'master'
+ pull_request:
+ branches: '*'
+
+jobs:
+ build:
+ runs-on: ubuntu-18.04
+ strategy:
+ max-parallel: 4
+ fail-fast: false
+ matrix:
+ python-version: ['3.8', '3.9', '3.10']
+ steps:
+ - uses: actions/checkout@v1
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install tox tox-gh-actions
+ - name: Test with tox
+ run: tox
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 00000000..9c6dea9a
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,14 @@
+version: 2
+
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.11"
+
+python:
+ install:
+ - requirements: docs/requirements.txt
+
+mkdocs:
+ configuration: mkdocs.yml
+ fail_on_warning: false
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 57c84096..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-language: python
-dist: xenial
-sudo: false
-
-install:
- - pip install tox
-
-matrix:
- include:
- - python: '3.6'
- env: TOXENV=check36
- - python: '3.8'
- env: TOXENV=check38
- - python: '3.4'
- env: TOXENV=py34
- - python: '3.5'
- env: TOXENV=py35
- - python: '3.6'
- env: TOXENV=py36
- - python: '3.7'
- env: TOXENV=py37
- - python: '3.8'
- env: TOXENV=py38
-
-script:
- - tox
-
-cache:
- pip: true
diff --git a/docs/Async Connections.md b/docs/Async Connections.md
index b4074be1..d655faff 100644
--- a/docs/Async Connections.md
+++ b/docs/Async Connections.md
@@ -1,3 +1,5 @@
+# Async Connections
+
Since the standard `query()` function is blocking, it can be a hazard for UI event loops. To deal with this, python-OBD has an `Async` connection object that can be used in place of the standard `OBD` object. `Async` is a subclass of `OBD`, and therefore inherits all of the standard methods. However, `Async` adds a few in order to control a threaded update loop. This loop will keep the values of your commands up to date with the vehicle. This way, when the user `query`s the car, the latest response is returned immediately.
The update loop is controlled by calling `start()` and `stop()`. To subscribe a command for updating, call `watch()` with your requested OBDCommand. Because the update loop is threaded, commands can only be `watch`ed while the loop is `stop`ed.
@@ -32,7 +34,7 @@ connection = obd.Async()
# a callback that prints every new value to the console
def new_rpm(r):
- print r.value
+ print (r.value)
connection.watch(obd.commands.RPM, callback=new_rpm)
connection.start()
diff --git a/docs/Command Lookup.md b/docs/Command Lookup.md
index 43e9ace7..f87ea39a 100644
--- a/docs/Command Lookup.md
+++ b/docs/Command Lookup.md
@@ -1,4 +1,6 @@
-`OBDCommand`s are objects used to query information from the vehicle. They contain all of the information neccessary to perform the query, and decode the cars response. Python-OBD has [built in tables](Command Tables.md) for the most common commands. They can be looked up by name, or by mode & PID.
+# Command Lookup
+
+`OBDCommand`s are objects used to query information from the vehicle. They contain all of the information necessary to perform the query and decode the car's response. Python-OBD has [built in tables](Command Tables.md) for the most common commands. They can be looked up by name or by mode & PID.
```python
import obd
diff --git a/docs/Command Tables.md b/docs/Command Tables.md
index 9b8d6e45..aebaf85d 100644
--- a/docs/Command Tables.md
+++ b/docs/Command Tables.md
@@ -1,4 +1,6 @@
-# OBD-II adapter (ELM327 commands)
+# Commands
+
+## OBD-II adapter (ELM327 commands)
|PID | Name | Description | Response Value |
|-----|-------------|-----------------------------------------|-----------------------|
@@ -7,7 +9,7 @@
-# Mode 01
+## Mode 01
|PID | Name | Description | Response Value |
|----|---------------------------|-----------------------------------------|-----------------------|
@@ -110,7 +112,7 @@
-# Mode 02
+## Mode 02
Mode 02 commands are the same as mode 01, but are metrics from when the last DTC occurred (the freeze frame). To access them by name, simple prepend `DTC_` to the Mode 01 command name.
@@ -124,7 +126,7 @@ obd.commands.DTC_RPM # the Mode 02 command
-# Mode 03
+## Mode 03
Mode 03 contains a single command `GET_DTC` which requests all diagnostic trouble codes from the vehicle. The response will contain the codes themselves, as well as a description (if python-OBD has one). See the [DTC Responses](Responses.md#diagnostic-trouble-codes-dtcs) section for more details.
@@ -135,7 +137,7 @@ Mode 03 contains a single command `GET_DTC` which requests all diagnostic troubl
-# Mode 04
+## Mode 04
|PID | Name | Description | Response Value |
|-----|-----------|-----------------------------------------|-----------------------|
@@ -143,7 +145,7 @@ Mode 03 contains a single command `GET_DTC` which requests all diagnostic troubl
-# Mode 06
+## Mode 06
*WARNING: mode 06 is experimental. While it passes software tests, it has not been tested on a real vehicle. Any debug output for this mode would be greatly appreciated.*
@@ -252,7 +254,7 @@ Mode 06 commands are used to monitor various test results from the vehicle. All
-# Mode 07
+## Mode 07
The return value will be encoded in the same structure as the Mode 03 `GET_DTC` command.
@@ -262,7 +264,7 @@ The return value will be encoded in the same structure as the Mode 03 `GET_DTC`
-# Mode 09
+## Mode 09
*WARNING: mode 09 is experimental. While it has been tested on a hardware simulator, only a subset of the supported
commands have (00-06) been tested. Any debug output for this mode, especially for the untested PIDs, would be greatly appreciated.*
diff --git a/docs/Connections.md b/docs/Connections.md
index fe314cdf..1df861fd 100644
--- a/docs/Connections.md
+++ b/docs/Connections.md
@@ -1,3 +1,4 @@
+# Connections
After installing the library, simply `import obd`, and create a new OBD connection object. By default, python-OBD will scan for Bluetooth and USB serial ports (in that order), and will pick the first connection it finds. The port can also be specified manually by passing a connection string to the OBD constructor. You can also use the `scan_serial` helper retrieve a list of connected ports.
diff --git a/docs/Custom Commands.md b/docs/Custom Commands.md
index 466deb29..e726030d 100644
--- a/docs/Custom Commands.md
+++ b/docs/Custom Commands.md
@@ -1,3 +1,4 @@
+# Custom Commands
If the command you need is not in python-OBDs tables, you can create a new `OBDCommand` object. The constructor accepts the following arguments (each will become a property).
@@ -13,8 +14,7 @@ If the command you need is not in python-OBDs tables, you can create a new `OBDC
| header (optional) | string | If set, use a custom header instead of the default one (7E0) |
-Example
--------
+## Example
```python
from obd import OBDCommand, Unit
@@ -58,7 +58,7 @@ Here are some details on the less intuitive fields of an OBDCommand:
---
-### OBDCommand.decoder
+## OBDCommand.decoder
The `decoder` argument is a function of following form.
@@ -83,7 +83,7 @@ def (messages):
---
-### OBDCommand.ecu
+## OBDCommand.ecu
The `ecu` argument is a constant used to filter incoming messages. Some commands may listen to multiple ECUs (such as DTC decoders), where others may only be concerned with the engine (such as RPM). Currently, python-OBD can only distinguish the engine, but this list may be expanded over time:
@@ -94,13 +94,13 @@ The `ecu` argument is a constant used to filter incoming messages. Some commands
---
-### OBDCommand.fast
+## OBDCommand.fast
The optional `fast` argument tells python-OBD whether it is safe to append a `"01"` to the end of the command. This will instruct the adapter to return the first response it recieves, rather than waiting for more (and eventually reaching a timeout). This can speed up requests significantly, and is enabled for most of python-OBDs internal commands. However, for unusual commands, it is safest to leave this disabled.
---
-### OBDCommand.header
+## OBDCommand.header
The optional `header` argument tells python-OBD to use a custom header when querying the command. If not set, python-OBD assumes that the default 7E0 header is needed for querying the command. The switch between default and custom header (and vice versa) is automatically done by python-OBD.
diff --git a/docs/Debug.md b/docs/Debug.md
index 0f929826..5e1df610 100644
--- a/docs/Debug.md
+++ b/docs/Debug.md
@@ -1,3 +1,5 @@
+# Debug
+
python-OBD uses python's builtin logging system. By default, it is setup to send output to `stderr` with a level of WARNING. The module's logger can be accessed via the `logger` variable at the root of the module. For instance, to enable console printing of all debug messages, use the following snippet:
```python
diff --git a/docs/Responses.md b/docs/Responses.md
index 30b992e6..0eef78f9 100644
--- a/docs/Responses.md
+++ b/docs/Responses.md
@@ -1,3 +1,5 @@
+# Responses
+
The `query()` function returns `OBDResponse` objects. These objects have the following properties:
| Property | Description |
@@ -11,7 +13,7 @@ The `query()` function returns `OBDResponse` objects. These objects have the fol
---
-### is_null()
+## is_null()
Use this function to check if a response is empty. Python-OBD will emit empty responses when it is unable to retrieve data from the car.
@@ -25,7 +27,7 @@ if not r.is_null():
---
-# Pint Values
+## Pint Values
The `value` property typically contains a [Pint](http://pint.readthedocs.io/en/latest/) `Quantity` object, but can also hold complex structures (depending on the request). Pint quantities combine a value and unit into a single class, and are used to represent physical values such as "4 seconds", and "88 mph". This allows for consistency when doing math and unit conversions. Pint maintains a registry of units, which is exposed in python-OBD as `obd.Unit`.
@@ -71,7 +73,7 @@ import obd
---
-# Status
+## Status
The status command returns information about the Malfunction Indicator Light (check-engine light), the number of trouble codes being thrown, and the type of engine.
@@ -111,7 +113,7 @@ Here are all of the tests names that python-OBD reports:
---
-# Diagnostic Trouble Codes (DTCs)
+## Diagnostic Trouble Codes (DTCs)
Each DTC is represented by a tuple containing the DTC code, and a description (if python-OBD has one). For commands that return multiple DTCs, a list is used.
@@ -129,7 +131,7 @@ response.value = ("P0104", "Mass or Volume Air Flow Circuit Intermittent")
---
-# Fuel Status
+## Fuel Status
The fuel status is a tuple of two strings, telling the status of the first and second fuel systems. Most cars only have one system, so the second element will likely be an empty string. The possible fuel statuses are:
@@ -144,7 +146,7 @@ The fuel status is a tuple of two strings, telling the status of the first and s
---
-# Air Status
+## Air Status
The air status will be one of these strings:
@@ -157,7 +159,7 @@ The air status will be one of these strings:
---
-# Oxygen Sensors Present
+## Oxygen Sensors Present
Returns a 2D structure of tuples (representing bank and sensor number), that holds boolean values for sensor presence.
@@ -183,7 +185,7 @@ response.value[1][2] == True # Bank 1, Sensor 2 is present
```
---
-# Monitors (Mode 06 Responses)
+## Monitors (Mode 06 Responses)
All mode 06 commands return `Monitor` objects holding various test results for the requested sensor. A single monitor response can hold multiple tests, in the form of `MonitorTest` objects. The OBD standard defines some tests, but vehicles can always implement custom tests beyond the standard. Here are the standard Test IDs (TIDs) that python-OBD will recognize:
diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md
index f2b9baca..7889e251 100644
--- a/docs/Troubleshooting.md
+++ b/docs/Troubleshooting.md
@@ -1,4 +1,3 @@
-
# Debug Output
If python-OBD is not working properly, the first thing you should do is enable debug output. Add the following line before your connection code to print all of the debug information to your console:
@@ -52,7 +51,7 @@ Here are some common logs from python-OBD, and their meanings:
### Unresponsive ELM
-```
+```none
[obd] ========================== python-OBD (v0.4.0) ==========================
[obd] Explicit port defined
[obd] Opening serial port '/dev/pts/2'
@@ -93,7 +92,7 @@ print ports # ['/dev/ttyUSB0', '/dev/ttyUSB1']
### Unresponsive Vehicle
-```
+```none
[obd] ========================== python-OBD (v0.4.0) ==========================
[obd] Explicit port defined
[obd] Opening serial port '/dev/pts/2'
diff --git a/docs/index.md b/docs/index.md
index 7688edea..890ffd1a 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,12 +1,14 @@
# Welcome
-Python-OBD is a library for handling data from a car's [**O**n-**B**oard **D**iagnostics port](https://en.wikipedia.org/wiki/On-board_diagnostics) (OBD-II). It can stream real time sensor data, perform diagnostics (such as reading check-engine codes), and is fit for the Raspberry Pi. This library is designed to work with standard [ELM327 OBD-II adapters](http://www.amazon.com/s/ref=nb_sb_noss?field-keywords=elm327).
+Python-OBD is a library for handling data from a car's [**O**n-**B**oard **D**iagnostics](https://en.wikipedia.org/wiki/On-board_diagnostics) port. Please keep in mind that the car **must** have OBD-II (any car made in 1996 and up); this will _**not**_ work with OBD-I.
+
+Python-OBD can stream real time sensor data, perform diagnostics (such as reading check-engine codes), and is fit for the Raspberry Pi. This library is designed to work with standard [ELM327 OBD-II adapters](http://www.amazon.com/s/ref=nb_sb_noss?field-keywords=elm327).
*NOTE: Python-OBD is below 1.0.0, meaning the API may change between minor versions. Consult the [GitHub release page](https://github.com/brendan-w/python-OBD/releases) for changelogs before updating.*
-# Installation
+## Installation
Install the latest release from pypi:
@@ -22,7 +24,7 @@ $ sudo apt-get install bluetooth bluez-utils blueman
-# Basic Usage
+## Basic Usage
```python
import obd
@@ -31,17 +33,17 @@ connection = obd.OBD() # auto-connects to USB or RF port
cmd = obd.commands.SPEED # select an OBD command (sensor)
-response = connection.query(cmd) # send the command, and parse the response
+response = connection.query(cmd) # send the command and parse the response
print(response.value) # returns unit-bearing values thanks to Pint
print(response.value.to("mph")) # user-friendly unit conversions
```
-OBD connections operate in a request-reply fashion. To retrieve data from the car, you must send commands that query for the data you want (e.g. RPM, Vehicle speed, etc). In python-OBD, this is done with the `query()` function. The commands themselves are represented as objects, and can be looked up by name or value in `obd.commands`. The `query()` function will return a response object with parsed data in its `value` property.
+OBD connections operate in a request-reply fashion. To retrieve data from the car, you must send commands that query for the data you want (e.g. RPM, Vehicle speed, etc). In python-OBD this is done with the `query()` function. The commands themselves are represented as objects and can be looked up by name or value in `obd.commands`. The `query()` function will return a response object with parsed data in its `value` property.
-# Module Layout
+## Module Layout
```python
import obd
@@ -59,7 +61,7 @@ obd.logger # the OBD module's root logger (for debug)
-# License
+## License
GNU General Public License V2
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 00000000..49ec98c5
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1 @@
+mkdocs==1.5.2
diff --git a/mkdocs.yml b/mkdocs.yml
index bec2ac65..ad9086bb 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -3,7 +3,7 @@ repo_url: https://github.com/brendan-w/python-OBD
repo_name: GitHub
extra_javascript:
- assets/extra.js
-pages:
+nav:
- 'Getting Started': 'index.md'
- 'OBD Connections': 'Connections.md'
- 'Command Lookup': 'Command Lookup.md'
diff --git a/obd/UnitsAndScaling.py b/obd/UnitsAndScaling.py
index b49650b1..fe0fae4d 100644
--- a/obd/UnitsAndScaling.py
+++ b/obd/UnitsAndScaling.py
@@ -36,8 +36,8 @@
# export the unit registry
Unit = pint.UnitRegistry()
-Unit.define("percent = [] = %")
Unit.define("ratio = []")
+Unit.define("percent = 1e-2 ratio = %")
Unit.define("gps = gram / second = GPS = grams_per_second")
Unit.define("lph = liter / hour = LPH = liters_per_hour")
Unit.define("ppm = count / 1000000 = PPM = parts_per_million")
diff --git a/obd/__version__.py b/obd/__version__.py
index f0788a87..1ef13195 100644
--- a/obd/__version__.py
+++ b/obd/__version__.py
@@ -1 +1 @@
-__version__ = '0.7.1'
+__version__ = '0.7.3'
diff --git a/obd/elm327.py b/obd/elm327.py
index db11355c..b543effc 100644
--- a/obd/elm327.py
+++ b/obd/elm327.py
@@ -55,7 +55,9 @@ class ELM327:
ecus()
"""
+ # chevron (ELM prompt character)
ELM_PROMPT = b'>'
+ # an 'OK' which indicates we are entering low power state
ELM_LP_ACTIVE = b'OK'
_SUPPORTED_PROTOCOLS = {
@@ -391,7 +393,7 @@ def low_power(self):
logger.info("cannot enter low power when unconnected")
return None
- lines = self.__send(b"ATLP", delay=1)
+ lines = self.__send(b"ATLP", delay=1, end_marker=self.ELM_LP_ACTIVE)
if 'OK' in lines:
logger.debug("Successfully entered low power mode")
@@ -466,13 +468,14 @@ def send_and_parse(self, cmd):
messages = self.__protocol(lines)
return messages
- def __send(self, cmd, delay=None):
+ def __send(self, cmd, delay=None, end_marker=ELM_PROMPT):
"""
unprotected send() function
will __write() the given string, no questions asked.
returns result of __read() (a list of line strings)
- after an optional delay.
+ after an optional delay, until the end marker (by
+ default, the prompt) is seen
"""
self.__write(cmd)
@@ -482,13 +485,13 @@ def __send(self, cmd, delay=None):
time.sleep(delay)
delayed += delay
- r = self.__read()
+ r = self.__read(end_marker=end_marker)
while delayed < 1.0 and len(r) <= 0:
d = 0.1
logger.debug("no response; wait: %f seconds" % d)
time.sleep(d)
delayed += d
- r = self.__read()
+ r = self.__read(end_marker=end_marker)
return r
def __write(self, cmd):
@@ -512,11 +515,12 @@ def __write(self, cmd):
else:
logger.info("cannot perform __write() when unconnected")
- def __read(self):
+ def __read(self, end_marker=ELM_PROMPT):
"""
"low-level" read function
- accumulates characters until the prompt character is seen
+ accumulates characters until the end marker (by
+ default, the prompt character) is seen
returns a list of [/r/n] delimited strings
"""
if not self.__port:
@@ -543,9 +547,8 @@ def __read(self):
buffer.extend(data)
- # end on chevron (ELM prompt character) or an 'OK' which
- # indicates we are entering low power state
- if self.ELM_PROMPT in buffer or self.ELM_LP_ACTIVE in buffer:
+ # end on specified end-marker sequence
+ if end_marker in buffer:
break
# log, and remove the "bytearray( ... )" part
diff --git a/obd/utils.py b/obd/utils.py
index 77cb36e2..221d3e9c 100644
--- a/obd/utils.py
+++ b/obd/utils.py
@@ -174,7 +174,7 @@ def scan_serial():
possible_ports += glob.glob("/dev/ttyUSB[0-9]*")
elif sys.platform.startswith('win'):
- possible_ports += ["\\.\COM%d" % i for i in range(256)]
+ possible_ports += [r"\\.\COM%d" % i for i in range(256)]
elif sys.platform.startswith('darwin'):
exclude = [
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..f91d6e3f
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,36 @@
+[project]
+name = "obd"
+version = "0.7.3"
+authors = [
+ { name="Brendan Whitfield", email="me@brendan-w.com" },
+ { name="Alistair Francis", email="alistair@alistair23.me" },
+ { name="Paul Bartek" },
+ { name="Peter Harris" },
+]
+description = "Serial module for handling live sensor data from a vehicle's OBD-II port"
+readme = "README.md"
+requires-python = ">=3.9"
+classifiers = [
+ "Operating System :: POSIX :: Linux",
+ "Topic :: System :: Monitoring",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
+ "Development Status :: 3 - Alpha",
+ "Topic :: System :: Logging",
+ "Intended Audience :: Developers",
+]
+keywords = ["obd", "obdii", "obd-ii", "obd2", "car", "serial", "vehicle", "diagnostic"]
+dependencies = [
+ "pyserial==3.*",
+ "pint==0.24.*",
+]
+license = "GPL-2.0-only"
+license-files = ["LICENSE"]
+
+[project.urls]
+Homepage = "https://github.com/brendan-w/python-OBD"
+Issues = "https://github.com/brendan-w/python-OBD/issues"
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 17a9c7e8..00000000
--- a/setup.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/env python
-# -*- coding: utf-8 -*-
-
-from setuptools import setup, find_packages
-
-with open("README.md", "r") as readme:
- long_description = readme.read()
-
-setup(
- name="obd",
- version="0.7.1",
- description=("Serial module for handling live sensor data from a vehicle's OBD-II port"),
- long_description=long_description,
- long_description_content_type="text/markdown",
- classifiers=[
- "Operating System :: POSIX :: Linux",
- "License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
- "Topic :: System :: Monitoring",
- "Programming Language :: Python :: 2",
- "Programming Language :: Python :: 3",
- "Development Status :: 3 - Alpha",
- "Topic :: System :: Logging",
- "Intended Audience :: Developers",
- ],
- keywords="obd obdii obd-ii obd2 car serial vehicle diagnostic",
- author="Brendan Whitfield",
- author_email="brendanw@windworksdesign.com",
- url="http://github.com/brendan-w/python-OBD",
- license="GNU GPLv2",
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- install_requires=["pyserial==3.*", "pint==0.7.*"],
-)
diff --git a/tests/README.md b/tests/README.md
index 2ecfa72e..5f9c4573 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -1,10 +1,34 @@
Testing
=======
-To test python-OBD, you will need to `pip install pytest` and install the module (preferably in a virtualenv) by running `python setup.py install`. The end-to-end tests will also require [obdsim](http://icculus.org/obdgpslogger/obdsim.html) to be running in the background. When starting obdsim, note the "SimPort name" that it creates, and pass it as an argument to py.test.
+To test python-OBD, you will need to install `pytest` and the `obd` module from your local tree (preferably in a virtualenv) by running:
-To run all tests, run the following command:
+```bash
+pip install pytest
+pip install build
+python -m build
+pip install ./dist/obd-0.7.2.tar.gz
+```
- $ py.test --port=/dev/pts/
+To run all basic python-only unit tests, run:
+
+```bash
+py.test
+```
+
+This directory also contains a set of end-to-end tests that require [obdsim](http://icculus.org/obdgpslogger/obdsim.html) to be running in the background. These tests are skipped by default, but can be activated by passing the `--port` flag.
+
+- Download `obdgpslogger`: https://icculus.org/obdgpslogger/downloads/obdgpslogger-0.16.tar.gz
+- Run the following build commands:
+ ```bash
+ mkdir build
+ cd build
+ cmake ..
+ make obdsim
+ ```
+- Start `./bin/obdsim`, note the `SimPort name: /dev/pts/` that it creates. Pass this pseudoterminal path as an argument to py.test:
+ ```bash
+ py.test --port=/dev/pts/
+ ```
For more information on pytest with virtualenvs, [read more here](https://pytest.org/dev/goodpractises.html)
\ No newline at end of file
diff --git a/tests/test_protocol.py b/tests/test_protocol.py
index b2757276..0c6ccc75 100644
--- a/tests/test_protocol.py
+++ b/tests/test_protocol.py
@@ -74,4 +74,4 @@ def test_populate_ecu_map():
# if no messages were received, then the map is empty
p = SAE_J1850_PWM([])
- assert len(p.ecu_map) == 0
+ assert p.ecu_map[p.TX_ID_ENGINE] == ECU.ENGINE
diff --git a/tox.ini b/tox.ini
index 2de0b4a1..6fe55f43 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,35 +1,33 @@
[tox]
envlist =
- check{36,38},
- py{34,35,36,37,38},
+ py{39,310,311,312,313},
coverage
+[gh-actions]
+python =
+ 3.9: py39
+ 3.10: py310
+ 3.11: py311
+ 3.12: py312
+ 3.13: py313
+
[testenv]
usedevelop = true
setenv =
COVERAGE_FILE={toxinidir}/.coverage_{envname}
deps =
- pdbpp==0.9.6
- pytest==3.10.1
- pytest-cov==2.6.1
-whitelist_externals =
- rm
+ pdbpp==0.10.3
+ pytest==7.2.1
+ pytest-cov==4.0.0
commands =
- rm -vf {toxinidir}/.coverage_{envname}
pytest --cov-report= --cov=obd {posargs}
-[testenv:check36]
-basepython = python3.6
-skipsdist = true
-
-
[testenv:coverage]
skipsdist = true
deps =
coverage
whitelist_externals =
/bin/bash
- rm
commands =
/bin/bash -c 'coverage combine {toxinidir}/.coverage_*'
coverage html -i
@@ -38,7 +36,6 @@ commands =
[flake8]
max-line-length = 120
-
[coverage:run]
omit =
.tox/*