Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/test-build-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.7"
python-version: "3.10"
- name: Install dependencies
run: |
bash foreach.sh install
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
matrix:
include:
- python-version: "3.7"
- python-version: "3.10"
arch: "ARM64"
- python-version: "3.13"
arch: "X64"
Expand Down
7 changes: 3 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@ exclude: |

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: mixed-line-ending
args: ["-f=lf"]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.11.6"
rev: "v0.12.12"
hooks:
- id: ruff
- id: ruff-check
args: ["--fix"]
- id: ruff-format
args: ["--preview"]

# documentation
- repo: https://github.com/sphinx-contrib/sphinx-lint
Expand Down
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# CHANGELOG

## v2.0.0 (TBD)

### Breaking Changes

- **Python Support**: Drop support for Python 3.7, 3.8, 3.9. Now requires Python 3.10+
- **esptool**: Update esptool requirement to >=5.1.dev1,<6 (from ~=4.9)
- **Deprecated Code Removal**:
- Remove `EsptoolArgs` class from `pytest-embedded-serial-esp`
- Remove deprecated parameters `hard_reset_after` and `no_stub` from `use_esptool()` decorator
- Remove deprecated `stub` property from `EspSerial` class (use `esp` instead)
- Remove deprecated `parse_test_menu()` and `parse_unity_menu_from_str()` methods from `IdfUnityDutMixin` (use `test_menu` property instead)
- Remove deprecated CLI option `--add-target-as-marker` (use `--add-target-as-marker-with-amount` instead)

### Migration Guide

1. **Python Version**: Upgrade to Python 3.10 or higher
2. **esptool**: Update esptool to version 5.1.dev1 or higher (but less than 6.0)
3. **Code Changes**:
- Replace `dut.stub` with `dut.esp`
- Replace `dut.parse_test_menu()` calls with `dut.test_menu` property access
- Replace `parse_unity_menu_from_str()` with `_parse_unity_menu_from_str()` if needed. `dut.test_menu` is preferred.
- Update CLI usage from `--add-target-as-marker` to `--add-target-as-marker-with-amount`
- Remove any usage of `EsptoolArgs` class
- Remove `hard_reset_after` and `no_stub` parameters from `use_esptool()` calls

## v1.17.0a0 (2025-08-07)

### Feat
Expand Down
4 changes: 2 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import shutil
import sys
import textwrap
from typing import List, Pattern
from re import Pattern

import pytest
from _pytest.config import Config
Expand Down Expand Up @@ -59,7 +59,7 @@ def cache_file_remove(cache_dir):

@pytest.fixture
def first_index_of_messages():
def _fake(_pattern: Pattern, _messages: List[str], _start: int = 0) -> int:
def _fake(_pattern: Pattern, _messages: list[str], _start: int = 0) -> int:
for i, _message in enumerate(_messages):
if _pattern.match(_message) and i >= _start:
return i
Expand Down
5 changes: 1 addition & 4 deletions pytest-embedded-arduino/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -29,7 +26,7 @@ classifiers = [
"Topic :: Software Development :: Testing",
]
dynamic = ["version", "description"]
requires-python = ">=3.7"
requires-python = ">=3.10"

dependencies = [
"pytest-embedded~=1.17.0a2",
Expand Down
8 changes: 4 additions & 4 deletions pytest-embedded-arduino/pytest_embedded_arduino/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import os
from typing import ClassVar, Dict, List, Tuple
from typing import ClassVar

from pytest_embedded.app import App

Expand All @@ -17,7 +17,7 @@ class ArduinoApp(App):
"""

#: dict of flash settings
flash_settings: ClassVar[Dict[str, Dict[str, str]]] = {
flash_settings: ClassVar[dict[str, dict[str, str]]] = {
'esp32': {'flash_mode': 'dio', 'flash_size': 'detect', 'flash_freq': '80m'},
'esp32s2': {'flash_mode': 'dio', 'flash_size': 'detect', 'flash_freq': '80m'},
'esp32c3': {'flash_mode': 'dio', 'flash_size': 'detect', 'flash_freq': '80m'},
Expand All @@ -28,7 +28,7 @@ class ArduinoApp(App):
}

#: dict of binaries' offset.
binary_offsets: ClassVar[Dict[str, List[int]]] = {
binary_offsets: ClassVar[dict[str, list[int]]] = {
'esp32': [0x1000, 0x8000, 0x10000],
'esp32s2': [0x1000, 0x8000, 0x10000],
'esp32c3': [0x0, 0x8000, 0x10000],
Expand Down Expand Up @@ -57,7 +57,7 @@ def _get_fqbn(self, build_path) -> str:
fqbn = options['fqbn']
return fqbn

def _get_bin_files(self, build_path, sketch, target) -> List[Tuple[int, str, bool]]:
def _get_bin_files(self, build_path, sketch, target) -> list[tuple[int, str, bool]]:
bootloader = os.path.realpath(os.path.join(build_path, sketch + '.ino.bootloader.bin'))
partitions = os.path.realpath(os.path.join(build_path, sketch + '.ino.partitions.bin'))
app = os.path.realpath(os.path.join(build_path, sketch + '.ino.bin'))
Expand Down
3 changes: 1 addition & 2 deletions pytest-embedded-arduino/pytest_embedded_arduino/serial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from typing import Optional

import esptool
from pytest_embedded_serial_esp.serial import EspSerial
Expand All @@ -19,7 +18,7 @@ class ArduinoSerial(EspSerial):
def __init__(
self,
app: ArduinoApp,
target: Optional[str] = None,
target: str | None = None,
**kwargs,
) -> None:
self.app = app
Expand Down
5 changes: 1 addition & 4 deletions pytest-embedded-idf/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -28,7 +25,7 @@ classifiers = [
"Topic :: Software Development :: Testing",
]
dynamic = ["version", "description"]
requires-python = ">=3.7"
requires-python = ">=3.10"

dependencies = [
"pytest-embedded~=1.17.0a2",
Expand Down
22 changes: 11 additions & 11 deletions pytest-embedded-idf/pytest_embedded_idf/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import shlex
import subprocess
import sys
from typing import Any, ClassVar, Dict, List, NamedTuple, Optional, Tuple
from typing import Any, ClassVar, NamedTuple

from pytest_embedded.app import App

Expand All @@ -26,8 +26,8 @@ class IdfApp(App):
flash_settings (dict[str, Any]): dict of flash settings
"""

XTENSA_TARGETS: ClassVar[List[str]] = ['esp32', 'esp32s2', 'esp32s3']
RISCV32_TARGETS: ClassVar[List[str]] = [
XTENSA_TARGETS: ClassVar[list[str]] = ['esp32', 'esp32s2', 'esp32s3']
RISCV32_TARGETS: ClassVar[list[str]] = [
'esp32c3',
'esp32c2',
'esp32c6',
Expand All @@ -44,7 +44,7 @@ class IdfApp(App):
def __init__(
self,
*args,
part_tool: Optional[str] = None,
part_tool: str | None = None,
**kwargs,
):
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -95,7 +95,7 @@ def parttool_path(self) -> str:
raise ValueError('Partition Tool not found. (Default: $IDF_PATH/components/partition_table/gen_esp32part.py)')

@property
def sdkconfig(self) -> Dict[str, Any]:
def sdkconfig(self) -> dict[str, Any]:
"""
Returns:
dict contains all k-v pairs from the sdkconfig file
Expand Down Expand Up @@ -143,7 +143,7 @@ def is_xtensa(self):
return False

@property
def partition_table(self) -> Dict[str, Any]:
def partition_table(self) -> dict[str, Any]:
"""
Returns:
partition table dict generated by the partition tool
Expand Down Expand Up @@ -187,14 +187,14 @@ def partition_table(self) -> Dict[str, Any]:
self._partition_table = partition_table
return self._partition_table

def _get_elf_file(self) -> Optional[str]:
def _get_elf_file(self) -> str | None:
for fn in os.listdir(self.binary_path):
if os.path.splitext(fn)[-1] == '.elf':
return os.path.realpath(os.path.join(self.binary_path, fn))

return None

def _get_bin_file(self) -> Optional[str]:
def _get_bin_file(self) -> str | None:
for fn in os.listdir(self.binary_path):
if os.path.splitext(fn)[-1] == '.bin':
return os.path.realpath(os.path.join(self.binary_path, fn))
Expand Down Expand Up @@ -229,7 +229,7 @@ def write_flash_args(self):

def _parse_flash_args_json(
self,
) -> Tuple[Dict[str, Any], List[FlashFile], Dict[str, str]]:
) -> tuple[dict[str, Any], list[FlashFile], dict[str, str]]:
flash_args_json_filepath = None
for fn in os.listdir(self.binary_path):
if fn == self.FLASH_ARGS_JSON_FILENAME:
Expand All @@ -242,7 +242,7 @@ def _parse_flash_args_json(
with open(flash_args_json_filepath) as fr:
flash_args = json.load(fr)

def _is_encrypted(_flash_args: Dict[str, Any], _offset: int, _file_path: str):
def _is_encrypted(_flash_args: dict[str, Any], _offset: int, _file_path: str):
for entry in _flash_args.values():
try:
if (entry['offset'], entry['file']) == (_offset, _file_path):
Expand All @@ -268,7 +268,7 @@ def _is_encrypted(_flash_args: Dict[str, Any], _offset: int, _file_path: str):

return flash_args, flash_files, flash_settings

def get_sha256(self, filepath: str) -> Optional[str]:
def get_sha256(self, filepath: str) -> str | None:
"""
Get the sha256 of the file

Expand Down
4 changes: 2 additions & 2 deletions pytest-embedded-idf/pytest_embedded_idf/dut.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__(
self,
app: IdfApp,
skip_check_coredump: bool = False,
panic_output_decode_script: t.Optional[str] = None,
panic_output_decode_script: str | None = None,
**kwargs,
) -> None:
self.target = app.target
Expand All @@ -72,7 +72,7 @@ def toolchain_prefix(self) -> str:
raise ValueError(f'Unknown target: {self.target}')

@property
def panic_output_decode_script(self) -> t.Optional[str]:
def panic_output_decode_script(self) -> str | None:
"""
Returns:
Panic output decode script path
Expand Down
28 changes: 15 additions & 13 deletions pytest-embedded-idf/pytest_embedded_idf/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
import os
import tempfile
from typing import Optional, TextIO, Union
from typing import TextIO

import esptool
from pytest_embedded_serial_esp.serial import EspSerial
Expand All @@ -24,7 +24,7 @@ class IdfSerial(EspSerial):
def __init__(
self,
app: IdfApp,
target: Optional[str] = None,
target: str | None = None,
confirm_target_elf_sha256: bool = False,
erase_nvs: bool = False,
**kwargs,
Expand Down Expand Up @@ -109,17 +109,19 @@ def load_ram(self) -> None:
esp=self.esp,
)

def _force_flag(self, app: Optional[IdfApp] = None):
def _force_flag(self, app: IdfApp | None = None):
if self.esp_flash_force:
return ['--force']

if app is None:
app = self.app

if any((
app.sdkconfig.get('SECURE_FLASH_ENC_ENABLED', False),
app.sdkconfig.get('SECURE_BOOT', False),
)):
if any(
(
app.sdkconfig.get('SECURE_FLASH_ENC_ENABLED', False),
app.sdkconfig.get('SECURE_BOOT', False),
)
):
return ['--force']

return []
Expand All @@ -132,7 +134,7 @@ def erase_flash(self, force: bool = False):
super().erase_flash()

@EspSerial.use_esptool()
def flash(self, app: Optional[IdfApp] = None) -> None:
def flash(self, app: IdfApp | None = None) -> None:
"""
Flash the `app.flash_files` to the dut
"""
Expand Down Expand Up @@ -203,11 +205,11 @@ def flash(self, app: Optional[IdfApp] = None) -> None:
@EspSerial.use_esptool()
def dump_flash(
self,
partition: Optional[str] = None,
address: Optional[str] = None,
size: Optional[str] = None,
output: Union[str, TextIO, None] = None,
) -> Optional[bytes]:
partition: str | None = None,
address: str | None = None,
size: str | None = None,
output: str | TextIO | None = None,
) -> bytes | None:
"""
Dump the flash bytes into the output file by partition name or by start address and size.

Expand Down
Loading
Loading