Skip to content

Commit 8a34747

Browse files
committed
fix(repl): resolve relative import paths against the working directory
Imports such as `Import Resource foo/my.resource` typed at the REPL prompt now resolve relative to the REPL's working directory, just like the same import does in a `.robot` file. Previously such imports only worked when the path was absolute, prefixed with `${CURDIR}/`, or reachable via the module search path. This matches Robot Framework's own resolution since RF 7.4. The REPL docs also note that on RF < 7.4 bare relative paths still fail (RF itself doesn't resolve them that way on those versions); use `${CURDIR}/...` or put the directory on the module search path instead.
1 parent f724aa2 commit 8a34747

3 files changed

Lines changed: 19 additions & 4 deletions

File tree

docs/03_reference/repl.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ robotcode repl -P ./libs -P ./vendor/python-libs
336336

337337
`-P` accepts the same `PATH` strings as `robot --pythonpath`.
338338

339+
> **Heads-up for Robot Framework < 7.4.** Bare relative paths in the BuiltIn import keywords `Import Resource` / `Import Library` / `Import Variables` (e.g. `Import Resource foo/my.resource`) only resolve against the directory of the importing file starting with RF 7.4. On older RF versions these keywords look the path up via the module search path only, so a bare relative form will fail with `Resource file '…' does not exist.` On those versions, either prefix the path with `${CURDIR}/` (e.g. `Import Resource ${CURDIR}/foo/my.resource`) or put the directory on the module search path. On RF 7.4+ the bare form just works.
340+
339341
## Pre-seeding variables
340342

341343
Variables can be set up before the prompt opens:

packages/repl/src/robotcode/repl/base_interpreter.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import abc
22
import signal
33
from datetime import datetime
4+
from io import StringIO
45
from pathlib import Path
56
from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Tuple, Union, cast
67

@@ -12,7 +13,6 @@
1213
from robot.running.context import EXECUTION_CONTEXTS
1314
from robot.running.signalhandler import STOP_SIGNAL_MONITOR, _StopSignalMonitor
1415

15-
from robotcode.core.utils.path import normalized_path
1616
from robotcode.robot.utils import RF_VERSION
1717
from robotcode.robot.utils.ast import iter_nodes
1818

@@ -137,6 +137,13 @@ def __init__(self) -> None:
137137
self.last_result: Any = None
138138
self.indent = 0
139139
self.source: Optional[Path] = None
140+
self._curdir: Optional[Path] = None
141+
142+
@property
143+
def curdir(self) -> Path:
144+
if self._curdir is None:
145+
self._curdir = self.source.parent if self.source is not None else Path.cwd()
146+
return self._curdir
140147

141148
def check_for_errors(self, node: Any) -> List[str]:
142149
if hasattr(node, "tokens"):
@@ -158,9 +165,11 @@ def get_test_body_from_string(self, command: str) -> Tuple[TestCase, List[str]]:
158165
+ ("\n ".join(command.split("\n")) if "\n" in command else command)
159166
) + "\n"
160167

161-
curdir = normalized_path(self.source).parent if self.source is not None else Path.cwd()
168+
with StringIO(suite_str) as source:
169+
model = get_model(source, curdir=str(self.curdir).replace("\\", "\\\\"))
170+
171+
model.source = self.source
162172

163-
model = get_model(suite_str, curdir=str(curdir).replace("\\", "\\\\"))
164173
suite: TestSuite = TestSuite.from_model(model)
165174

166175
errors: List[str] = []

packages/repl/src/robotcode/repl/run.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ def run_repl(
7676

7777
root_folder, _profile, cmd_options = handle_robot_options(app, (*robot_options_and_args, *(str(f) for f in files)))
7878

79+
if source is None:
80+
source = Path.cwd() / "__repl_internal__.robot"
81+
7982
with app.chdir(root_folder) as orig_folder:
8083
try:
8184
curdir = normalized_path(source).parent if source is not None else Path.cwd()
@@ -88,7 +91,7 @@ def run_repl(
8891
orig_folder=orig_folder,
8992
).parse_arguments((*cmd_options, *robot_options_and_args))
9093

91-
interpreter.source = source
94+
interpreter.source = normalized_path(source) if source is not None else None
9295

9396
settings = RobotSettings(
9497
options,
@@ -113,6 +116,7 @@ def run_repl(
113116

114117
with io.StringIO(REPL_SUITE) as suite_io:
115118
model = get_model(suite_io, curdir=str(curdir).replace("\\", "\\\\"))
119+
model.source = source
116120

117121
suite = TestSuite.from_model(model)
118122
suite.configure(**settings.suite_config)

0 commit comments

Comments
 (0)