mirror of
https://github.com/esphome/esphome.git
synced 2026-05-24 09:56:46 +08:00
[core] Move platformio files to subfolder (#16347)
This commit is contained in:
+35
-33
@@ -766,24 +766,24 @@ def compile_program(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
_LOGGER.info("Compiling app... Build path: %s", CORE.build_path)
|
||||
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import api
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
rc = api.run_compile(config, CORE.verbose)
|
||||
rc = toolchain.run_compile(config, CORE.verbose)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
# Create factory.bin, ota.bin, and firmware.elf copy
|
||||
api.create_factory_bin()
|
||||
api.create_ota_bin()
|
||||
api.create_elf_copy()
|
||||
toolchain.create_factory_bin()
|
||||
toolchain.create_ota_bin()
|
||||
toolchain.create_elf_copy()
|
||||
else:
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
rc = platformio_api.run_compile(config, CORE.verbose)
|
||||
rc = toolchain.run_compile(config, CORE.verbose)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if idedata is None:
|
||||
return 1
|
||||
|
||||
@@ -879,13 +879,15 @@ def upload_using_esptool(
|
||||
if file is not None:
|
||||
flash_images = [FlashImage(path=file, offset="0x0")]
|
||||
elif CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import api
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
flash_images = [FlashImage(path=api.get_factory_firmware_path(), offset="0x0")]
|
||||
flash_images = [
|
||||
FlashImage(path=toolchain.get_factory_firmware_path(), offset="0x0")
|
||||
]
|
||||
else:
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
|
||||
firmware_offset = "0x10000" if CORE.is_esp32 else "0x0"
|
||||
flash_images = [
|
||||
@@ -958,13 +960,13 @@ def upload_using_esptool(
|
||||
|
||||
|
||||
def upload_using_platformio(config: ConfigType, port: str) -> int:
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
# RP2040 platform-raspberrypi build recipe expects firmware.bin.signed for
|
||||
# the upload target, but 'nobuild' skips the build phase that creates it.
|
||||
# Create it here so the upload doesn't fail.
|
||||
if CORE.data.get(KEY_CORE, {}).get(KEY_TARGET_PLATFORM) == PLATFORM_RP2040:
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
build_dir = Path(idedata.firmware_elf_path).parent
|
||||
firmware_bin = build_dir / "firmware.bin"
|
||||
signed_bin = build_dir / "firmware.bin.signed"
|
||||
@@ -974,15 +976,15 @@ def upload_using_platformio(config: ConfigType, port: str) -> int:
|
||||
upload_args = ["-t", "upload", "-t", "nobuild"]
|
||||
if port is not None:
|
||||
upload_args += ["--upload-port", port]
|
||||
return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args)
|
||||
return toolchain.run_platformio_cli_run(config, CORE.verbose, *upload_args)
|
||||
|
||||
|
||||
def _find_picotool() -> Path | None:
|
||||
"""Find the picotool binary from PlatformIO packages."""
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
try:
|
||||
idedata = platformio_api.get_idedata(CORE.config)
|
||||
idedata = toolchain.get_idedata(CORE.config)
|
||||
except Exception: # noqa: BLE001 # pylint: disable=broad-except
|
||||
return None
|
||||
return get_picotool_path(idedata.cc_path)
|
||||
@@ -995,9 +997,9 @@ def upload_using_picotool(config: ConfigType) -> int:
|
||||
the mass storage copy approach that causes "disk not ejected properly"
|
||||
warnings on macOS.
|
||||
"""
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
firmware_elf = Path(idedata.firmware_elf_path)
|
||||
|
||||
if not firmware_elf.is_file():
|
||||
@@ -1457,11 +1459,11 @@ def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
return exit_code
|
||||
if CORE.is_host:
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import api
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
program_path = str(api.get_elf_path())
|
||||
program_path = str(toolchain.get_elf_path())
|
||||
else:
|
||||
from esphome.platformio_api import get_idedata
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
_LOGGER.info("Successfully compiled program to path '%s'", program_path)
|
||||
@@ -1515,11 +1517,11 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
_LOGGER.info("Successfully compiled program.")
|
||||
if CORE.is_host:
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import api
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
program_path = str(api.get_elf_path())
|
||||
program_path = str(toolchain.get_elf_path())
|
||||
else:
|
||||
from esphome.platformio_api import get_idedata
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
_LOGGER.info("Running program from path '%s'", program_path)
|
||||
@@ -1719,12 +1721,12 @@ def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
)
|
||||
return 1
|
||||
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
logging.disable(logging.INFO)
|
||||
logging.disable(logging.WARNING)
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if idedata is None:
|
||||
return 1
|
||||
|
||||
@@ -1753,16 +1755,16 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
# Get idedata for analysis
|
||||
idedata = None
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import api
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
objdump_path = str(api.get_objdump_path())
|
||||
readelf_path = str(api.get_readelf_path())
|
||||
objdump_path = str(toolchain.get_objdump_path())
|
||||
readelf_path = str(toolchain.get_readelf_path())
|
||||
|
||||
firmware_elf = api.get_elf_path()
|
||||
firmware_elf = toolchain.get_elf_path()
|
||||
else:
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if idedata is None:
|
||||
_LOGGER.error("Failed to get IDE data for memory analysis")
|
||||
return 1
|
||||
|
||||
@@ -24,7 +24,7 @@ from .helpers import (
|
||||
from .toolchain import find_tool, resolve_tool_path, run_tool
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from esphome.platformio_api import IDEData
|
||||
from esphome.platformio.toolchain import IDEData
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -739,7 +739,7 @@ def main():
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from esphome.platformio_api import IDEData
|
||||
from esphome.platformio.toolchain import IDEData
|
||||
|
||||
build_path = Path(build_dir)
|
||||
|
||||
|
||||
@@ -2582,9 +2582,9 @@ def copy_files():
|
||||
|
||||
|
||||
def _decode_pc(config, addr):
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if not idedata.addr2line_path or not idedata.firmware_elf_path:
|
||||
_LOGGER.debug("decode_pc no addr2line")
|
||||
return
|
||||
|
||||
@@ -463,9 +463,9 @@ ESP8266_EXCEPTION_CODES = {
|
||||
|
||||
|
||||
def _decode_pc(config, addr):
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if not idedata.addr2line_path or not idedata.firmware_elf_path:
|
||||
_LOGGER.debug("decode_pc no addr2line")
|
||||
return
|
||||
|
||||
@@ -397,11 +397,11 @@ def get_download_types(storage_json: StorageJSON) -> list[dict[str, str]]:
|
||||
def _upload_using_platformio(
|
||||
config: ConfigType, port: str, upload_args: list[str]
|
||||
) -> int | str:
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
if port is not None:
|
||||
upload_args += ["--upload-port", port]
|
||||
return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args)
|
||||
return toolchain.run_platformio_cli_run(config, CORE.verbose, *upload_args)
|
||||
|
||||
|
||||
def upload_program(config: ConfigType, args, host: str) -> bool:
|
||||
|
||||
@@ -510,7 +510,7 @@ def process_stacktrace(config, line: str, backtrace_state: bool) -> bool:
|
||||
|
||||
if backtrace_state:
|
||||
if match := _CRASH_ADDR_RE.search(line):
|
||||
from esphome.platformio_api import get_idedata
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
|
||||
idedata = get_idedata(config)
|
||||
if idedata.addr2line_path:
|
||||
|
||||
@@ -40,8 +40,9 @@ import voluptuous as vol
|
||||
import yaml
|
||||
from yaml.nodes import Node
|
||||
|
||||
from esphome import const, platformio_api, yaml_util
|
||||
from esphome import const, yaml_util
|
||||
from esphome.helpers import get_bool_env, mkdir_p, sort_ip_addresses
|
||||
from esphome.platformio import toolchain
|
||||
from esphome.storage_json import (
|
||||
StorageJSON,
|
||||
archive_storage_path,
|
||||
@@ -1090,7 +1091,7 @@ class DownloadBinaryRequestHandler(BaseHandler):
|
||||
self.send_error(404 if rc == 2 else 500)
|
||||
return
|
||||
|
||||
idedata = platformio_api.IDEData(json.loads(stdout))
|
||||
idedata = toolchain.IDEData(json.loads(stdout))
|
||||
|
||||
found = False
|
||||
for image in idedata.extra_flash_images:
|
||||
|
||||
@@ -190,7 +190,7 @@ def main() -> int:
|
||||
|
||||
script_path = sys.argv[1]
|
||||
|
||||
# Mirror the platformio_runner behaviour: verbose mode disables the
|
||||
# Mirror the platformio runner behaviour: verbose mode disables the
|
||||
# line filter so all output reaches the user.
|
||||
is_verbose = any(arg in ("-v", "--verbose") for arg in sys.argv[2:])
|
||||
filter_lines = None if is_verbose else FILTER_IDF_LINES or None
|
||||
|
||||
@@ -15,7 +15,7 @@ from esphome.espidf.framework import check_esp_idf_install, get_framework_env
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = "espidf_api"
|
||||
DOMAIN = "espidf_toolchain"
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Subprocess entry point that applies ESPHome's PlatformIO patches.
|
||||
|
||||
Invoked via ``python -m esphome.platformio_runner`` instead of
|
||||
Invoked via ``python -m esphome.platformio.runner`` instead of
|
||||
``python -m platformio`` so that the patches (incremental rebuild
|
||||
preservation, download retries) apply inside the subprocess. Running
|
||||
PlatformIO in a subprocess keeps its ``sys.path`` mutations and other
|
||||
@@ -64,7 +64,7 @@ def run_platformio_cli(*args, **kwargs) -> str | int:
|
||||
# a user-provided value (or the unmodified path on platforms that
|
||||
# don't need the strip).
|
||||
os.environ["PYTHONEXEPATH"] = python_exe
|
||||
cmd = [python_exe, "-m", "esphome.platformio_runner"] + list(args)
|
||||
cmd = [python_exe, "-m", "esphome.platformio.runner"] + list(args)
|
||||
|
||||
return run_external_process(*cmd, **kwargs)
|
||||
|
||||
@@ -23,7 +23,7 @@ from esphome.config import validate_config
|
||||
from esphome.const import CONF_PLATFORM
|
||||
from esphome.core import CORE
|
||||
from esphome.loader import get_component, get_platform
|
||||
from esphome.platformio_api import get_idedata
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
from tests.testing_helpers import ComponentManifestOverride, set_testing_manifest
|
||||
|
||||
# This must coincide with the version in /platformio.ini
|
||||
|
||||
@@ -26,7 +26,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
from esphome.analyze_memory import MemoryAnalyzer
|
||||
from esphome.platformio_api import IDEData
|
||||
from esphome.platformio.toolchain import IDEData
|
||||
from script.ci_helpers import write_github_output
|
||||
|
||||
# Regex patterns for extracting memory usage from PlatformIO output
|
||||
|
||||
@@ -128,8 +128,8 @@ def mock_storage_json() -> Generator[MagicMock]:
|
||||
|
||||
@pytest.fixture
|
||||
def mock_idedata() -> Generator[MagicMock]:
|
||||
"""Fixture to mock platformio_api.IDEData."""
|
||||
with patch("esphome.dashboard.web_server.platformio_api.IDEData") as mock:
|
||||
"""Fixture to mock platformio toolchain.IDEData."""
|
||||
with patch("esphome.dashboard.web_server.toolchain.IDEData") as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import pytest_asyncio
|
||||
|
||||
import esphome.config
|
||||
from esphome.core import CORE
|
||||
from esphome.platformio_api import get_idedata
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
|
||||
from .const import (
|
||||
API_CONNECTION_TIMEOUT,
|
||||
|
||||
@@ -64,15 +64,15 @@ def mock_copy_file_if_changed() -> Generator[Mock, None, None]:
|
||||
|
||||
@pytest.fixture
|
||||
def mock_run_platformio_cli() -> Generator[Mock, None, None]:
|
||||
"""Mock run_platformio_cli for platformio_api."""
|
||||
with patch("esphome.platformio_api.run_platformio_cli") as mock:
|
||||
"""Mock run_platformio_cli for platformio toolchain."""
|
||||
with patch("esphome.platformio.toolchain.run_platformio_cli") as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_run_platformio_cli_run() -> Generator[Mock, None, None]:
|
||||
"""Mock run_platformio_cli_run for platformio_api."""
|
||||
with patch("esphome.platformio_api.run_platformio_cli_run") as mock:
|
||||
"""Mock run_platformio_cli_run for platformio toolchain."""
|
||||
with patch("esphome.platformio.toolchain.run_platformio_cli_run") as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
@@ -92,8 +92,8 @@ def mock_esp8266_decode_pc() -> Generator[Mock, None, None]:
|
||||
|
||||
@pytest.fixture
|
||||
def mock_run_external_process() -> Generator[Mock, None, None]:
|
||||
"""Mock run_external_process for platformio_api."""
|
||||
with patch("esphome.platformio_api.run_external_process") as mock:
|
||||
"""Mock run_external_process for platformio toolchain."""
|
||||
with patch("esphome.platformio.toolchain.run_external_process") as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
@@ -113,8 +113,8 @@ def mock_subprocess_run() -> Generator[Mock, None, None]:
|
||||
|
||||
@pytest.fixture
|
||||
def mock_get_idedata() -> Generator[Mock, None, None]:
|
||||
"""Mock get_idedata for platformio_api."""
|
||||
with patch("esphome.platformio_api.get_idedata") as mock:
|
||||
"""Mock get_idedata for platformio toolchain."""
|
||||
with patch("esphome.platformio.toolchain.get_idedata") as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import pytest
|
||||
from pytest import CaptureFixture
|
||||
from zeroconf import ServiceStateChange
|
||||
|
||||
from esphome import platformio_api
|
||||
from esphome.__main__ import (
|
||||
Purpose,
|
||||
_get_configured_xtal_freq,
|
||||
@@ -96,6 +95,7 @@ from esphome.espota2 import (
|
||||
OTA_TYPE_UPDATE_BOOTLOADER,
|
||||
OTA_TYPE_UPDATE_PARTITION_TABLE,
|
||||
)
|
||||
from esphome.platformio import toolchain
|
||||
from esphome.util import BootselResult, FlashImage
|
||||
from esphome.zeroconf import _await_discovery, discover_mdns_devices
|
||||
|
||||
@@ -287,7 +287,7 @@ def mock_run_external_process() -> Generator[Mock]:
|
||||
|
||||
@pytest.fixture
|
||||
def mock_run_external_command_main() -> Generator[Mock]:
|
||||
"""Mock run_external_command in __main__ module (different from platformio_api)."""
|
||||
"""Mock run_external_command in __main__ module (different from platformio toolchain)."""
|
||||
with patch("esphome.__main__.run_external_command") as mock:
|
||||
mock.return_value = 0 # Default to success
|
||||
yield mock
|
||||
@@ -1199,7 +1199,7 @@ def test_upload_using_esptool_path_conversion(
|
||||
CORE.data[KEY_ESP32] = {KEY_VARIANT: VARIANT_ESP32}
|
||||
|
||||
# Create mock IDEData with Path objects
|
||||
mock_idedata = MagicMock(spec=platformio_api.IDEData)
|
||||
mock_idedata = MagicMock(spec=toolchain.IDEData)
|
||||
mock_idedata.firmware_bin_path = tmp_path / "firmware.bin"
|
||||
mock_idedata.extra_flash_images = [
|
||||
FlashImage(path=tmp_path / "bootloader.bin", offset="0x1000"),
|
||||
@@ -1277,7 +1277,7 @@ def test_upload_using_esptool_skips_missing_extra_flash_images(
|
||||
|
||||
missing_path = tmp_path / "variants" / "tasmota" / "tinyuf2.bin"
|
||||
|
||||
mock_idedata = MagicMock(spec=platformio_api.IDEData)
|
||||
mock_idedata = MagicMock(spec=toolchain.IDEData)
|
||||
mock_idedata.firmware_bin_path = tmp_path / "firmware.bin"
|
||||
mock_idedata.extra_flash_images = [
|
||||
FlashImage(path=tmp_path / "bootloader.bin", offset="0x1000"),
|
||||
@@ -1389,8 +1389,8 @@ def test_upload_using_platformio_creates_signed_bin_for_rp2040(
|
||||
mock_idedata.firmware_elf_path = str(firmware_elf)
|
||||
|
||||
with (
|
||||
patch("esphome.platformio_api.get_idedata", return_value=mock_idedata),
|
||||
patch("esphome.platformio_api.run_platformio_cli_run", return_value=0),
|
||||
patch("esphome.platformio.toolchain.get_idedata", return_value=mock_idedata),
|
||||
patch("esphome.platformio.toolchain.run_platformio_cli_run", return_value=0),
|
||||
):
|
||||
result = upload_using_platformio({}, "/dev/ttyACM0")
|
||||
|
||||
@@ -1406,7 +1406,7 @@ def test_upload_using_platformio_skips_signed_bin_for_non_rp2040(
|
||||
"""Test that upload_using_platformio doesn't create signed bin for non-RP2040."""
|
||||
setup_core(platform=PLATFORM_ESP32)
|
||||
|
||||
with patch("esphome.platformio_api.run_platformio_cli_run", return_value=0):
|
||||
with patch("esphome.platformio.toolchain.run_platformio_cli_run", return_value=0):
|
||||
result = upload_using_platformio({}, "/dev/ttyUSB0")
|
||||
|
||||
assert result == 0
|
||||
@@ -1504,7 +1504,7 @@ def test_upload_using_picotool_success(tmp_path: Path) -> None:
|
||||
|
||||
config = {}
|
||||
with (
|
||||
patch("esphome.platformio_api.get_idedata", return_value=mock_idedata),
|
||||
patch("esphome.platformio.toolchain.get_idedata", return_value=mock_idedata),
|
||||
patch("subprocess.run", return_value=mock_result),
|
||||
):
|
||||
exit_code = upload_using_picotool(config)
|
||||
@@ -1524,7 +1524,7 @@ def test_upload_using_picotool_no_elf(tmp_path: Path) -> None:
|
||||
mock_idedata.cc_path = "/fake/path/gcc"
|
||||
|
||||
config = {}
|
||||
with patch("esphome.platformio_api.get_idedata", return_value=mock_idedata):
|
||||
with patch("esphome.platformio.toolchain.get_idedata", return_value=mock_idedata):
|
||||
exit_code = upload_using_picotool(config)
|
||||
|
||||
assert exit_code == 1
|
||||
@@ -1544,7 +1544,7 @@ def test_upload_using_picotool_not_found(tmp_path: Path) -> None:
|
||||
mock_idedata.cc_path = "/fake/path/gcc"
|
||||
|
||||
config = {}
|
||||
with patch("esphome.platformio_api.get_idedata", return_value=mock_idedata):
|
||||
with patch("esphome.platformio.toolchain.get_idedata", return_value=mock_idedata):
|
||||
exit_code = upload_using_picotool(config)
|
||||
|
||||
assert exit_code == 1
|
||||
@@ -1578,7 +1578,7 @@ def test_upload_using_picotool_permission_error(tmp_path: Path) -> None:
|
||||
|
||||
config = {}
|
||||
with (
|
||||
patch("esphome.platformio_api.get_idedata", return_value=mock_idedata),
|
||||
patch("esphome.platformio.toolchain.get_idedata", return_value=mock_idedata),
|
||||
patch("subprocess.run", return_value=mock_result),
|
||||
):
|
||||
exit_code = upload_using_picotool(config)
|
||||
@@ -4696,7 +4696,7 @@ def test_command_analyze_memory_success(
|
||||
firmware_elf.write_text("mock elf file")
|
||||
|
||||
# Mock idedata
|
||||
mock_idedata_obj = MagicMock(spec=platformio_api.IDEData)
|
||||
mock_idedata_obj = MagicMock(spec=toolchain.IDEData)
|
||||
mock_idedata_obj.firmware_elf_path = str(firmware_elf)
|
||||
mock_idedata_obj.objdump_path = "/path/to/objdump"
|
||||
mock_idedata_obj.readelf_path = "/path/to/readelf"
|
||||
@@ -4768,7 +4768,7 @@ def test_command_analyze_memory_with_external_components(
|
||||
firmware_elf.write_text("mock elf file")
|
||||
|
||||
# Mock idedata
|
||||
mock_idedata_obj = MagicMock(spec=platformio_api.IDEData)
|
||||
mock_idedata_obj = MagicMock(spec=toolchain.IDEData)
|
||||
mock_idedata_obj.firmware_elf_path = str(firmware_elf)
|
||||
mock_idedata_obj.objdump_path = "/path/to/objdump"
|
||||
mock_idedata_obj.readelf_path = "/path/to/readelf"
|
||||
@@ -4859,16 +4859,18 @@ def test_command_analyze_memory_no_idedata(
|
||||
|
||||
@pytest.fixture
|
||||
def mock_compile_build_info_run_compile() -> Generator[Mock]:
|
||||
"""Mock platformio_api.run_compile for build_info tests."""
|
||||
with patch("esphome.platformio_api.run_compile", return_value=0) as mock:
|
||||
"""Mock toolchain.run_compile for build_info tests."""
|
||||
with patch("esphome.platformio.toolchain.run_compile", return_value=0) as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_compile_build_info_get_idedata() -> Generator[Mock]:
|
||||
"""Mock platformio_api.get_idedata for build_info tests."""
|
||||
"""Mock toolchain.get_idedata for build_info tests."""
|
||||
mock_idedata = MagicMock()
|
||||
with patch("esphome.platformio_api.get_idedata", return_value=mock_idedata) as mock:
|
||||
with patch(
|
||||
"esphome.platformio.toolchain.get_idedata", return_value=mock_idedata
|
||||
) as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
@@ -5778,7 +5780,7 @@ def test_upload_using_esptool_passes_crystal_callback(
|
||||
sdkconfig = build_dir / "sdkconfig.test"
|
||||
sdkconfig.write_text("CONFIG_XTAL_FREQ=40\n")
|
||||
|
||||
mock_idedata = MagicMock(spec=platformio_api.IDEData)
|
||||
mock_idedata = MagicMock(spec=toolchain.IDEData)
|
||||
mock_idedata.firmware_bin_path = tmp_path / "firmware.bin"
|
||||
mock_idedata.extra_flash_images = []
|
||||
mock_get_idedata.return_value = mock_idedata
|
||||
@@ -5808,7 +5810,7 @@ def test_upload_using_esptool_subprocess_passes_crystal_callback(
|
||||
sdkconfig = build_dir / "sdkconfig.test"
|
||||
sdkconfig.write_text("CONFIG_XTAL_FREQ=40\n")
|
||||
|
||||
mock_idedata = MagicMock(spec=platformio_api.IDEData)
|
||||
mock_idedata = MagicMock(spec=toolchain.IDEData)
|
||||
mock_idedata.firmware_bin_path = tmp_path / "firmware.bin"
|
||||
mock_idedata.extra_flash_images = []
|
||||
mock_get_idedata.return_value = mock_idedata
|
||||
|
||||
+49
-51
@@ -1,4 +1,4 @@
|
||||
"""Tests for platformio_api.py path functions."""
|
||||
"""Tests for esphome.platformio.toolchain path functions."""
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
@@ -11,8 +11,8 @@ from unittest.mock import MagicMock, Mock, call, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome import platformio_api, platformio_runner
|
||||
from esphome.core import CORE, EsphomeError
|
||||
from esphome.platformio import runner, toolchain
|
||||
from esphome.util import FlashImage
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ def test_idedata_firmware_elf_path(setup_core: Path) -> None:
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
CORE.name = "test"
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf"}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
assert idedata.firmware_elf_path == Path("/path/to/firmware.elf")
|
||||
|
||||
@@ -32,7 +32,7 @@ def test_idedata_firmware_bin_path(setup_core: Path) -> None:
|
||||
CORE.name = "test"
|
||||
prog_path = str(Path("/path/to/firmware.elf"))
|
||||
raw_data = {"prog_path": prog_path}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.firmware_bin_path
|
||||
assert isinstance(result, Path)
|
||||
@@ -47,7 +47,7 @@ def test_idedata_firmware_bin_path_preserves_directory(setup_core: Path) -> None
|
||||
CORE.name = "test"
|
||||
prog_path = str(Path("/complex/path/to/build/firmware.elf"))
|
||||
raw_data = {"prog_path": prog_path}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.firmware_bin_path
|
||||
expected = Path("/complex/path/to/build/firmware.bin")
|
||||
@@ -67,7 +67,7 @@ def test_idedata_extra_flash_images(setup_core: Path) -> None:
|
||||
]
|
||||
},
|
||||
}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
images = idedata.extra_flash_images
|
||||
assert len(images) == 2
|
||||
@@ -83,7 +83,7 @@ def test_idedata_extra_flash_images_empty(setup_core: Path) -> None:
|
||||
CORE.build_path = setup_core / "build" / "test"
|
||||
CORE.name = "test"
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf", "extra": {"flash_images": []}}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
images = idedata.extra_flash_images
|
||||
assert images == []
|
||||
@@ -97,7 +97,7 @@ def test_idedata_cc_path(setup_core: Path) -> None:
|
||||
"prog_path": "/path/to/firmware.elf",
|
||||
"cc_path": "/Users/test/.platformio/packages/toolchain-xtensa32/bin/xtensa-esp32-elf-gcc",
|
||||
}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
assert (
|
||||
idedata.cc_path
|
||||
@@ -132,7 +132,7 @@ def test_load_idedata_returns_dict(
|
||||
mock_run_platformio_cli_run.return_value = '{"prog_path": "/test/firmware.elf"}'
|
||||
|
||||
config = {"name": "test"}
|
||||
result = platformio_api._load_idedata(config)
|
||||
result = toolchain._load_idedata(config)
|
||||
|
||||
assert result is not None
|
||||
assert isinstance(result, dict)
|
||||
@@ -161,7 +161,7 @@ def test_load_idedata_uses_cache_when_valid(
|
||||
os.utime(idedata_path, (platformio_ini_mtime + 1, platformio_ini_mtime + 1))
|
||||
|
||||
config = {"name": "test"}
|
||||
result = platformio_api._load_idedata(config)
|
||||
result = toolchain._load_idedata(config)
|
||||
|
||||
# Should not call _run_idedata since cache is valid
|
||||
mock_run_platformio_cli_run.assert_not_called()
|
||||
@@ -194,7 +194,7 @@ def test_load_idedata_regenerates_when_platformio_ini_newer(
|
||||
mock_run_platformio_cli_run.return_value = json.dumps(new_data)
|
||||
|
||||
config = {"name": "test"}
|
||||
result = platformio_api._load_idedata(config)
|
||||
result = toolchain._load_idedata(config)
|
||||
|
||||
# Should call _run_idedata since platformio.ini is newer
|
||||
mock_run_platformio_cli_run.assert_called_once()
|
||||
@@ -228,7 +228,7 @@ def test_load_idedata_regenerates_on_corrupted_cache(
|
||||
mock_run_platformio_cli_run.return_value = json.dumps(new_data)
|
||||
|
||||
config = {"name": "test"}
|
||||
result = platformio_api._load_idedata(config)
|
||||
result = toolchain._load_idedata(config)
|
||||
|
||||
# Should call _run_idedata since cache is corrupted
|
||||
mock_run_platformio_cli_run.assert_called_once()
|
||||
@@ -253,7 +253,7 @@ def test_run_idedata_parses_json_from_output(
|
||||
f"Some preamble\n{json.dumps(expected_data)}\nSome postamble"
|
||||
)
|
||||
|
||||
result = platformio_api._run_idedata(config)
|
||||
result = toolchain._run_idedata(config)
|
||||
|
||||
assert result == expected_data
|
||||
|
||||
@@ -267,7 +267,7 @@ def test_run_idedata_raises_on_no_json(
|
||||
mock_run_platformio_cli_run.return_value = "No JSON in this output"
|
||||
|
||||
with pytest.raises(EsphomeError):
|
||||
platformio_api._run_idedata(config)
|
||||
toolchain._run_idedata(config)
|
||||
|
||||
|
||||
def test_run_idedata_raises_on_invalid_json(
|
||||
@@ -279,7 +279,7 @@ def test_run_idedata_raises_on_invalid_json(
|
||||
|
||||
# The ValueError from json.loads is re-raised
|
||||
with pytest.raises(ValueError):
|
||||
platformio_api._run_idedata(config)
|
||||
toolchain._run_idedata(config)
|
||||
|
||||
|
||||
def test_run_platformio_cli_sets_environment_variables(
|
||||
@@ -290,7 +290,7 @@ def test_run_platformio_cli_sets_environment_variables(
|
||||
|
||||
with patch.dict(os.environ, {}, clear=False):
|
||||
mock_run_external_process.return_value = 0
|
||||
platformio_api.run_platformio_cli("test", "arg")
|
||||
toolchain.run_platformio_cli("test", "arg")
|
||||
|
||||
# Check environment variables were set
|
||||
assert os.environ["PLATFORMIO_FORCE_COLOR"] == "true"
|
||||
@@ -303,11 +303,11 @@ def test_run_platformio_cli_sets_environment_variables(
|
||||
assert "PYTHONWARNINGS" in os.environ
|
||||
|
||||
# Check command was called correctly — runs PlatformIO as a subprocess
|
||||
# via the esphome.platformio_runner entry point.
|
||||
# via the esphome.platformio.runner entry point.
|
||||
mock_run_external_process.assert_called_once()
|
||||
args = mock_run_external_process.call_args[0]
|
||||
assert "-m" in args
|
||||
assert "esphome.platformio_runner" in args
|
||||
assert "esphome.platformio.runner" in args
|
||||
assert "test" in args
|
||||
assert "arg" in args
|
||||
|
||||
@@ -342,8 +342,8 @@ def test_strip_win_long_path_prefix(
|
||||
platform: str, input_path: str, expected: str
|
||||
) -> None:
|
||||
r"""``\\?\`` and ``\\?\UNC\`` prefixes are stripped only on win32."""
|
||||
with patch("esphome.platformio_api.sys.platform", platform):
|
||||
assert platformio_api._strip_win_long_path_prefix(input_path) == expected
|
||||
with patch("esphome.platformio.toolchain.sys.platform", platform):
|
||||
assert toolchain._strip_win_long_path_prefix(input_path) == expected
|
||||
|
||||
|
||||
def test_run_platformio_cli_strips_win_long_path_prefix(
|
||||
@@ -366,15 +366,15 @@ def test_run_platformio_cli_strips_win_long_path_prefix(
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=False),
|
||||
patch("esphome.platformio_api.sys.platform", "win32"),
|
||||
patch("esphome.platformio_api.sys.executable", prefixed_exe),
|
||||
patch("esphome.platformio.toolchain.sys.platform", "win32"),
|
||||
patch("esphome.platformio.toolchain.sys.executable", prefixed_exe),
|
||||
):
|
||||
# Pop any pre-existing PYTHONEXEPATH so the assertion below reflects
|
||||
# what run_platformio_cli set, not whatever the test runner's
|
||||
# environment happened to contain.
|
||||
os.environ.pop("PYTHONEXEPATH", None)
|
||||
mock_run_external_process.return_value = 0
|
||||
platformio_api.run_platformio_cli("test", "arg")
|
||||
toolchain.run_platformio_cli("test", "arg")
|
||||
|
||||
# The subprocess is invoked with the stripped executable path.
|
||||
mock_run_external_process.assert_called_once()
|
||||
@@ -398,12 +398,12 @@ def test_run_platformio_cli_does_not_set_pythonexepath_without_strip(
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=False),
|
||||
patch("esphome.platformio_api.sys.platform", "linux"),
|
||||
patch("esphome.platformio_api.sys.executable", plain_exe),
|
||||
patch("esphome.platformio.toolchain.sys.platform", "linux"),
|
||||
patch("esphome.platformio.toolchain.sys.executable", plain_exe),
|
||||
):
|
||||
os.environ.pop("PYTHONEXEPATH", None)
|
||||
mock_run_external_process.return_value = 0
|
||||
platformio_api.run_platformio_cli("test", "arg")
|
||||
toolchain.run_platformio_cli("test", "arg")
|
||||
|
||||
mock_run_external_process.assert_called_once()
|
||||
args = mock_run_external_process.call_args[0]
|
||||
@@ -419,7 +419,7 @@ def test_run_platformio_cli_run_builds_command(
|
||||
mock_run_platformio_cli.return_value = 0
|
||||
|
||||
config = {"name": "test"}
|
||||
platformio_api.run_platformio_cli_run(config, True, "extra", "args")
|
||||
toolchain.run_platformio_cli_run(config, True, "extra", "args")
|
||||
|
||||
mock_run_platformio_cli.assert_called_once_with(
|
||||
"run", "-d", CORE.build_path, "-v", "extra", "args"
|
||||
@@ -434,7 +434,7 @@ def test_run_compile(setup_core: Path, mock_run_platformio_cli_run: Mock) -> Non
|
||||
config = {CONF_ESPHOME: {CONF_COMPILE_PROCESS_LIMIT: 4}}
|
||||
mock_run_platformio_cli_run.return_value = 0
|
||||
|
||||
platformio_api.run_compile(config, verbose=True)
|
||||
toolchain.run_compile(config, verbose=True)
|
||||
|
||||
mock_run_platformio_cli_run.assert_called_once_with(config, True, "-j4")
|
||||
|
||||
@@ -461,22 +461,22 @@ def test_get_idedata_caches_result(
|
||||
config = {"name": "test"}
|
||||
|
||||
# First call should load and cache
|
||||
result1 = platformio_api.get_idedata(config)
|
||||
result1 = toolchain.get_idedata(config)
|
||||
mock_run_platformio_cli_run.assert_called_once()
|
||||
|
||||
# Second call should use cache from CORE.data
|
||||
result2 = platformio_api.get_idedata(config)
|
||||
result2 = toolchain.get_idedata(config)
|
||||
mock_run_platformio_cli_run.assert_called_once() # Still only called once
|
||||
|
||||
assert result1 is result2
|
||||
assert isinstance(result1, platformio_api.IDEData)
|
||||
assert isinstance(result1, toolchain.IDEData)
|
||||
assert result1.firmware_elf_path == Path("/test/firmware.elf")
|
||||
|
||||
|
||||
def test_idedata_addr2line_path_windows(setup_core: Path) -> None:
|
||||
"""Test IDEData.addr2line_path on Windows."""
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf", "cc_path": "C:\\tools\\gcc.exe"}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.addr2line_path
|
||||
assert result == "C:\\tools\\addr2line.exe"
|
||||
@@ -485,7 +485,7 @@ def test_idedata_addr2line_path_windows(setup_core: Path) -> None:
|
||||
def test_idedata_addr2line_path_unix(setup_core: Path) -> None:
|
||||
"""Test IDEData.addr2line_path on Unix."""
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf", "cc_path": "/usr/bin/gcc"}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.addr2line_path
|
||||
assert result == "/usr/bin/addr2line"
|
||||
@@ -494,7 +494,7 @@ def test_idedata_addr2line_path_unix(setup_core: Path) -> None:
|
||||
def test_idedata_objdump_path_windows(setup_core: Path) -> None:
|
||||
"""Test IDEData.objdump_path on Windows."""
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf", "cc_path": "C:\\tools\\gcc.exe"}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.objdump_path
|
||||
assert result == "C:\\tools\\objdump.exe"
|
||||
@@ -503,7 +503,7 @@ def test_idedata_objdump_path_windows(setup_core: Path) -> None:
|
||||
def test_idedata_objdump_path_unix(setup_core: Path) -> None:
|
||||
"""Test IDEData.objdump_path on Unix."""
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf", "cc_path": "/usr/bin/gcc"}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.objdump_path
|
||||
assert result == "/usr/bin/objdump"
|
||||
@@ -512,7 +512,7 @@ def test_idedata_objdump_path_unix(setup_core: Path) -> None:
|
||||
def test_idedata_readelf_path_windows(setup_core: Path) -> None:
|
||||
"""Test IDEData.readelf_path on Windows."""
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf", "cc_path": "C:\\tools\\gcc.exe"}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.readelf_path
|
||||
assert result == "C:\\tools\\readelf.exe"
|
||||
@@ -521,7 +521,7 @@ def test_idedata_readelf_path_windows(setup_core: Path) -> None:
|
||||
def test_idedata_readelf_path_unix(setup_core: Path) -> None:
|
||||
"""Test IDEData.readelf_path on Unix."""
|
||||
raw_data = {"prog_path": "/path/to/firmware.elf", "cc_path": "/usr/bin/gcc"}
|
||||
idedata = platformio_api.IDEData(raw_data)
|
||||
idedata = toolchain.IDEData(raw_data)
|
||||
|
||||
result = idedata.readelf_path
|
||||
assert result == "/usr/bin/readelf"
|
||||
@@ -547,7 +547,7 @@ def test_patch_structhash(setup_core: Path) -> None:
|
||||
},
|
||||
):
|
||||
# Call patch_structhash
|
||||
platformio_runner.patch_structhash()
|
||||
runner.patch_structhash()
|
||||
|
||||
# Verify both modules had clean_build_dir patched
|
||||
# Check that clean_build_dir was set on both modules
|
||||
@@ -599,7 +599,7 @@ def test_patched_clean_build_dir_removes_outdated(setup_core: Path) -> None:
|
||||
},
|
||||
):
|
||||
# Call patch_structhash to install the patched function
|
||||
platformio_runner.patch_structhash()
|
||||
runner.patch_structhash()
|
||||
|
||||
# Call the patched function
|
||||
mock_helpers.clean_build_dir(str(build_dir), [])
|
||||
@@ -649,7 +649,7 @@ def test_patched_clean_build_dir_keeps_updated(setup_core: Path) -> None:
|
||||
},
|
||||
):
|
||||
# Call patch_structhash to install the patched function
|
||||
platformio_runner.patch_structhash()
|
||||
runner.patch_structhash()
|
||||
|
||||
# Call the patched function
|
||||
mock_helpers.clean_build_dir(str(build_dir), [])
|
||||
@@ -697,7 +697,7 @@ def test_patched_clean_build_dir_creates_missing(setup_core: Path) -> None:
|
||||
},
|
||||
):
|
||||
# Call patch_structhash to install the patched function
|
||||
platformio_runner.patch_structhash()
|
||||
runner.patch_structhash()
|
||||
|
||||
# Call the patched function
|
||||
mock_helpers.clean_build_dir(str(build_dir), [])
|
||||
@@ -727,7 +727,7 @@ def test_patch_file_downloader_succeeds_first_try() -> None:
|
||||
),
|
||||
},
|
||||
):
|
||||
platformio_runner.patch_file_downloader()
|
||||
runner.patch_file_downloader()
|
||||
|
||||
from platformio.package.download import FileDownloader
|
||||
|
||||
@@ -766,7 +766,7 @@ def test_patch_file_downloader_retries_on_failure() -> None:
|
||||
),
|
||||
patch("time.sleep") as mock_sleep,
|
||||
):
|
||||
platformio_runner.patch_file_downloader()
|
||||
runner.patch_file_downloader()
|
||||
|
||||
from platformio.package.download import FileDownloader
|
||||
|
||||
@@ -807,7 +807,7 @@ def test_patch_file_downloader_raises_after_max_retries() -> None:
|
||||
),
|
||||
patch("time.sleep") as mock_sleep,
|
||||
):
|
||||
platformio_runner.patch_file_downloader()
|
||||
runner.patch_file_downloader()
|
||||
|
||||
from platformio.package.download import FileDownloader
|
||||
|
||||
@@ -855,7 +855,7 @@ def test_patch_file_downloader_closes_session_and_response_between_retries() ->
|
||||
),
|
||||
patch("time.sleep"),
|
||||
):
|
||||
platformio_runner.patch_file_downloader()
|
||||
runner.patch_file_downloader()
|
||||
|
||||
from platformio.package.download import FileDownloader
|
||||
|
||||
@@ -890,9 +890,9 @@ def test_patch_file_downloader_idempotent() -> None:
|
||||
},
|
||||
):
|
||||
# Patch multiple times
|
||||
platformio_runner.patch_file_downloader()
|
||||
platformio_runner.patch_file_downloader()
|
||||
platformio_runner.patch_file_downloader()
|
||||
runner.patch_file_downloader()
|
||||
runner.patch_file_downloader()
|
||||
runner.patch_file_downloader()
|
||||
|
||||
from platformio.package.download import FileDownloader
|
||||
|
||||
@@ -910,9 +910,7 @@ def _filter_through_redirect(line: str) -> str:
|
||||
from esphome.util import RedirectText
|
||||
|
||||
captured = io.StringIO()
|
||||
redirect = RedirectText(
|
||||
captured, filter_lines=platformio_runner.FILTER_PLATFORMIO_LINES
|
||||
)
|
||||
redirect = RedirectText(captured, filter_lines=runner.FILTER_PLATFORMIO_LINES)
|
||||
redirect.write(line + "\n")
|
||||
return captured.getvalue()
|
||||
|
||||
Reference in New Issue
Block a user