cold-cricket-31243
01/13/2025, 5:45 PMawait run_interactive_process(InteractiveProcess(...)
. From the comments across the channels, it's looking like I need to use mocking with rule_runner.run_interactive_process
like we see in this example to test the plugin. Can someone confirm if this is the correct approach? The issue I'm facing right now is attached. TLDR native_engine.IntrinsicError: Error executing interactive process: No such file or directory (os error 2)
. From the log error, I know the issue is related to the files being written in one directory, but the pants goal being run in a different directory.cold-cricket-31243
01/13/2025, 11:14 PMhappy-kitchen-89482
01/14/2025, 12:16 AMhappy-kitchen-89482
01/14/2025, 12:17 AMhappy-kitchen-89482
01/14/2025, 12:17 AMcold-cricket-31243
01/14/2025, 12:41 AMcold-cricket-31243
01/14/2025, 12:45 AMfrom pants.backend.python.target_types import PythonSourceTarget
from pants.testutil.rule_runner import RuleRunner, mock_console
from pants_uv_lifecycle_plugin import run_uv_sync
from pants_uv_lifecycle_plugin.run_uv_sync import UvSyncGoal, run_uv_sync_on_pyproject_directories
import pytest
from textwrap import dedent
from pathlib import Path
@pytest.fixture
def uv_sync_rule_runner() -> RuleRunner:
return RuleRunner(target_types=[PythonSourceTarget], rules=[*run_uv_sync.rules()])
def test_run_uv_sync(uv_sync_rule_runner: RuleRunner) -> None:
uv_sync_rule_runner.write_files(
{
"test-project/src/test_project/__init__.py": "",
"test-project/src/BUILD": "python_sources()",
"test-project/BUILD": "python_requirements(name=\"reqs\",source=\"pyproject.toml\")",
"test-project/pyproject.toml": dedent(
"""\
[project]
name = "test-project"
version = "0.1.0"
description = "A simple uv project to test the pants-uv-lifecycle-plugin"
readme = "README.md"
authors = [{ name = "aiSSEMBLE Baseline Community", email = "<mailto:aissemble@bah.com|aissemble@bah.com>"}]
requires-python = ">=3.9"
dependencies = ["numpy>=2.2.1"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
"""),
"test-project/README.md": "",
}
)
assert Path(uv_sync_rule_runner.build_root, "test-project/src/test_project/__init__.py").read_text() == ""
assert Path(uv_sync_rule_runner.build_root, "test-project/src/BUILD").read_text() == "python_sources()"
assert Path(uv_sync_rule_runner.build_root, "test-project/BUILD").read_text() == "python_requirements(name=\"reqs\",source=\"pyproject.toml\")"
assert Path(uv_sync_rule_runner.build_root, "test-project/README.md").read_text() == ""
assert Path(uv_sync_rule_runner.build_root, "test-project/pyproject.toml").read_text() == dedent(
"""\
[project]
name = "test-project"
version = "0.1.0"
description = "A simple uv project to test the pants-uv-lifecycle-plugin"
readme = "README.md"
authors = [{ name = "aiSSEMBLE Baseline Community", email = "<mailto:aissemble@bah.com|aissemble@bah.com>"}]
requires-python = ">=3.9"
dependencies = ["numpy>=2.2.1"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
""")
with mock_console(uv_sync_rule_runner.options_bootstrapper) as (console, _):
result = uv_sync_rule_runner.run_goal_rule(UvSyncGoal)
assert result.exit_code == 0, f"The result.exit_code is {result.exit_code}, but 0 was expected."
The error I'm getting is below. I suspect that the No such file or directory
is due to the fact that the RuleRunner doesn't have access to the PATH
environment variable. Does anything jump out at you as far as what I could be doing wrong?
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/testutil/rule_runner.py:440: in run_goal_rule
exit_code = self.scheduler.run_goal_rule(
/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/internals/scheduler.py:564: in run_goal_rule
(return_value,) = self.product_request(
/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/internals/scheduler.py:593: in product_request
return self.execute(request)
/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/internals/scheduler.py:534: in execute
self._raise_on_error([t for _, t in throws])
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <pants.engine.internals.scheduler.SchedulerSession object at 0x106fd81c0>
throws = [Throw(exc=IntrinsicError('Error executing interactive process: No such file or directory (os error 2)'), python_trace...ack=[('pants_uv_lifecycle_plugin.run_uv_sync.run_uv_sync_on_pyproject_directories', 'run `uv sync`'), ('root', None)])]
def _raise_on_error(self, throws: list[Throw]) -> NoReturn:
exception_noun = pluralize(len(throws), "Exception")
others_msg = f"\n(and {len(throws) - 1} more)\n" if len(throws) > 1 else ""
> raise ExecutionError(
f"{exception_noun} encountered:\n\n"
f"{throws[0].render(self._scheduler.include_trace_on_error)}\n"
f"{others_msg}",
wrapped_exceptions=tuple(t.exc for t in throws),
)
E pants.engine.internals.scheduler.ExecutionError: 1 Exception encountered:
E
E Engine traceback:
E in root
E ..
E in pants_uv_lifecycle_plugin.run_uv_sync.run_uv_sync_on_pyproject_directories
E run `uv sync`
E
E Traceback (most recent call last):
E File "src/pants_uv_lifecycle_plugin/run_uv_sync.py", line 31, in run_uv_sync_on_pyproject_directories
E interactive_process_result = await run_interactive_process(
E File "/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/intrinsics.py", line 157, in run_interactive_process
E ret: InteractiveProcessResult = await _interactive_process(process, **implicitly())
E File "/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/rules.py", line 74, in wrapper
E return await call
E File "/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 85, in __await__
E result = yield self
E File "/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/intrinsics.py", line 147, in _interactive_process
E return await native_engine.interactive_process(process, process_execution_environment)
E native_engine.IntrinsicError: Error executing interactive process: No such file or directory (os error 2)
/Users/margaretblack/.cache/pants/named_caches/pex_root/venvs/a16dc0cecf9dbe98a962c4fa657b20606c9475de/08044421b45091240ec153bb89d50a6331335fa0/lib/python3.9/site-packages/pants/engine/internals/scheduler.py:518: ExecutionError
- generated xml file: tests.test_run_uv_sync.py.pants-uv-lifecycle-plugin-tests.xml -
=========================== short test summary info ============================
FAILED tests/test_run_uv_sync.py::test_run_uv_sync - pants.engine.internals.s...
============================== 1 failed in 0.91s ===============================
cold-cricket-31243
01/14/2025, 2:05 PMcold-cricket-31243
01/14/2025, 3:41 PMhappy-kitchen-89482
01/14/2025, 6:14 PMhappy-kitchen-89482
01/14/2025, 6:15 PMrun_pants()
is the most expensive way (your test starts up an entire pants
process) but it is often very effectivecold-cricket-31243
01/14/2025, 6:18 PMbehave
instead.