Checkpoint Lab — Resource Files, Variable Files, Library Imports, and Project Layout
Refactor and prove a portable multi-file Robot Framework project, run it from two working directories under one command contract, diagnose an import-path failure and keyword collision, and produce an evidence-backed dependency diagram.
Learning objectives
- Build the complete disposable project from an empty directory with explicit source/output boundaries.
- Predict how CURDIR, EXECDIR, module search path, and result locations change across two launch directories.
- Inject and diagnose one import-path failure without losing the first-failure artifacts.
- Inject and diagnose one duplicate-keyword collision and repair the ownership boundary.
- Produce a dependency diagram, verification checklist, and cleanup plan suitable for CI handoff.
Current compatibility baseline. Verified
2026-08-31: Robot Framework 7.4.2 is the current stable release and
requires Python 3.8+; 7.5b1 is a pre-release and is not required in
this chapter. In 7.4.2, .resource is the recommended
resource-file extension. Resource and Settings-level variable-file
paths are resolved relative to the importing data file first and
then via Python's module search path. ${CURDIR} is the
absolute directory of the current data file;
${EXECDIR} is the absolute directory where execution
started. JSON variable files require no optional package; YAML
variable files require PyYAML.
1. Checkpoint contract and safety boundary
Create a fresh rf12-checkpoint directory using only
synthetic strings/files. The mandatory path uses Robot Framework
core, BuiltIn/OperatingSystem/String, one tiny local Python library,
one Python variable file, and one JSON variable file. No network,
browser, API, database, SSH, Remote library, container, CI account,
production credential, or paid service is required.
Failure injection is source-only and reversible. Do not modify global PYTHONPATH, system Python, production files, or shared CI configuration. Preserve each failing result directory before repair.
2. Preflight and exact assumptions
python --version
python -m robot --version
python -c "import os, sys; print('cwd=', os.getcwd()); print('python=', sys.executable)"
Required baseline: Robot Framework 7.4.2 on Python 3.8+. Record the actual Python version. JSON uses the Python standard library and needs no optional package. Pabot, Browser/Selenium, external API/database/SSH libraries, CI providers, and containers are not used.
3. Build the project tree
rf12-checkpoint/
├── tests/
│ └── labels.robot
├── resources/
│ ├── labels.resource
│ └── collision.resource # added only during failure injection
├── variables/
│ ├── demo.py
│ └── demo.json
├── libraries/
│ ├── __init__.py
│ └── text_tools.py
├── data/
│ └── sample-label.txt
└── results/
├── dryrun/
├── root-run/
├── other-cwd-run/
├── broken-import/
├── repaired-import/
├── collision/
└── repaired-collision/
4. Implement the clean source files
# variables/demo.py
PREFIX = "build-"
EXPECTED = "BUILD-ALPHA"
{
"fixture_name": "sample-label.txt",
"expected_file_value": "build-beta"
}
# libraries/text_tools.py
def normalize_label(value: str) -> str:
return value.strip().upper()
*** Settings ***
Library libraries.text_tools
Library OperatingSystem
Library String
Variables ../variables/demo.py
Variables ../variables/demo.json
*** Keywords ***
Label Should Normalize
[Arguments] ${raw} ${expected}
${actual}= Normalize Label ${raw}
Should Be Equal ${actual} ${expected}
Fixture Label Should Match
${path}= Set Variable ${CURDIR}/../data/${fixture_name}
${raw}= Get File ${path}
${raw}= Strip String ${raw}
Should Be Equal ${raw} ${expected_file_value}
*** Settings ***
Resource ../resources/labels.resource
*** Test Cases ***
Configured normalization
Label Should Normalize ${PREFIX}alpha ${EXPECTED}
Source-relative fixture
Fixture Label Should Match
Path evidence
Log suite CURDIR=${CURDIR}
Log EXECDIR=${EXECDIR}
build-beta
5. Write predictions before running
| Prediction | Expected result | Independent verification |
|---|---|---|
| Moving cwd changes EXECDIR | Different absolute launch directories | Compare log.html Path evidence calls |
| Moving cwd does not break Resource/Variables imports | Both runs PASS | Report + import logs |
| Fixture path stays source-owned | Reads the same data/sample-label.txt |
Resource CURDIR-derived path in log/source |
| Project-root pythonpath finds library |
libraries.text_tools imports in both runs
|
Libdoc + Python __file__ |
| Results are isolated | Each run writes only to its named result directory | Directory tree / git status |
6. Establish one documented command contract
Define RF12_ROOT as the absolute checkpoint root. From
any directory, the execution contract is:
python -m robot --pythonpath "$RF12_ROOT" --outputdir "$RF12_ROOT/results/RUN_NAME" "$RF12_ROOT/tests"
PowerShell uses the same semantic contract with
$env:RF12_ROOT. Only RUN_NAME changes so
evidence is not overwritten. The project does not depend on the
current directory for imports or fixture lookup.
7. Dry-run and Libdoc verification
python -m robot --pythonpath "$RF12_ROOT" --dryrun --outputdir "$RF12_ROOT/results/dryrun" "$RF12_ROOT/tests"
python -m robot.libdoc --pythonpath "$RF12_ROOT" libraries.text_tools "$RF12_ROOT/results/text-tools.html"
python -m robot.libdoc --pythonpath "$RF12_ROOT" "$RF12_ROOT/resources/labels.resource" "$RF12_ROOT/results/labels-resource.html"
Expected: dry-run PASS and two Libdoc files generated. Record the exact commands and file paths in the evidence packet.
8. Execute from two working directories
Run A: change directory to
$RF12_ROOT and use RUN_NAME=root-run.
Run B: change directory to a safe unrelated
directory such as its parent or your temporary directory and use
RUN_NAME=other-cwd-run.
Both runs should PASS. The EXECDIR log differs. The
suite/resource import graph, Python library identity, fixture value,
and test results remain the same.
9. Failure injection 1: break one Resource path
Change only this line in tests/labels.robot:
# Broken on purpose:
Resource labels.resource
Run with RUN_NAME=broken-import. Preserve the console
output and all generated artifacts. Use the diagnostic sequence:
importer is tests/labels.robot;
labels.resource is not beside that file; module-search
fallback does not provide such a resource. Repair to
../resources/labels.resource, then run
RUN_NAME=repaired-import.
10. Failure injection 2: create a duplicate keyword owner
# resources/collision.resource
*** Keywords ***
Label Should Normalize
[Arguments] ${raw} ${expected}
Fail Deliberate duplicate owner should not be selected implicitly.
Import collision.resource beside
labels.resource in the suite and keep the unqualified
call. Run with RUN_NAME=collision and preserve the
ambiguity/failure evidence. Then:
-
Qualify the intended call as
labels.Label Should Normalizeto prove resolution. - Remove the duplicate resource import and delete the synthetic collision file.
-
Run
RUN_NAME=repaired-collisionand confirm PASS.
The final architecture has one domain owner; qualification is diagnostic evidence, not permanent permission for duplicated abstractions.
11. Produce the final dependency diagram
flowchart TD T[tests/labels.robot] --> R[resources/labels.resource] R --> VP[variables/demo.py] R --> VJ[variables/demo.json] R --> L[libraries.text_tools] R --> F[data/sample-label.txt] P[--pythonpath project root] --> L T --> O[results/RUN_NAME] O -. evidence only .-> T
Annotate the diagram in your evidence notes: Resource/Variables
source paths are owned by the importing files; the Python library is
found through the runner-supplied project root; the data file is
addressed from the resource's ${CURDIR}; result files
flow outward and are never imported back into source.
12. Required evidence packet
- Python and Robot Framework version output.
- Project tree before and after the refactor.
- The exact
RF12_ROOT-based command contract. - Dry-run output and both Libdoc files.
-
Root-run and other-cwd-run
output.xml/log.html/report.html. -
Logged
CURDIR/EXECDIRobservations from both launch locations. - Broken-import console/result evidence and repaired-import evidence.
- Keyword-collision evidence, qualified diagnostic call, and final repaired-collision evidence.
-
Python library
__file__provenance if module identity was in doubt. - Final dependency diagram and a one-paragraph path/import convention.
13. Verification checklist
- Exactly one project-root search-path contract is documented.
- No absolute developer-specific path is committed in Robot source.
- No brittle cwd-relative import is required.
- Both working-directory runs PASS with the same test behavior.
- The two injected failures were preserved in separate result directories before repair.
- No duplicate keyword owner remains in the final source.
- No Python variable file performs network calls, random generation, secret logging, or filesystem mutation at import time.
- JSON is the only non-Python variable format required; YAML/PyYAML remains optional.
- Generated results stay under
results/. - No real secret, PII, production URL, or destructive target appears in source or evidence.
14. Cleanup / rollback
The lab creates only the disposable
rf12-checkpoint tree. Archive the evidence packet first
if required. Then remove only that verified lab directory. Do not
use a recursive delete command with an empty/unverified variable. If
this project is in Git, confirm
git status --short before deleting anything so you do
not remove unrelated work.
15. What Chapter 12 adds to a production operating model
You now have an explicit import/dependency contract: source-relative files are owned by their importer; local Python modules are resolved through a documented root or installed package; variable imports stay deterministic and low-side-effect; keyword collisions are never chosen accidentally; outputs have a separate evidence root. This is the portability foundation needed before Chapter 13 adds assertion/error/recovery policies across these reusable layers.
16. Knowledge check
Why do both cwd runs pass even though EXECDIR changes?
The runner supplies an absolute project root for module discovery, source-owned files use source-relative/CURDIR paths, and the input suite is addressed from the documented root. None of the required imports depend on cwd.
What does the broken Resource path prove?
Resource paths are not implicitly relative to a project root. The importing file and module-search fallback determine resolution.
Why preserve the duplicate-keyword failure before qualifying the call?
The original ambiguity is diagnostic evidence. Qualification proves which owner is intended; preserving both runs demonstrates that the repair addressed resolution rather than hiding the failure.
When should libraries.text_tools stop relying on --pythonpath?
When it becomes a mature reusable library shared across repositories, package/install it with explicit versions so Python discovery comes from the environment rather than repository-specific source-path injection.
What does Chapter 13 add next?
Assertions, error handling, expected failures, and recovery patterns—how failures should propagate and be diagnosed across the reusable architecture built here.
17. Checkpoint complete
You can now design and prove a portable multi-file Robot Framework project. Imports have explicit owners, path semantics survive different launch directories, variable formats/dependencies are documented, Python module identity is observable, collisions and broken paths are diagnosed without guesswork, and result artifacts remain separate from source. Chapter 13 builds trustworthy failure semantics on top of this layout.
Further reading
- Robot Framework 7.4.2 User Guide — Resource and variable files — resource structure, import rules, Python/YAML/JSON variable files, and precedence.
- Robot Framework 7.4.2 User Guide — Using test libraries — importing libraries by name or path and library aliases.
-
Robot Framework 7.4.2 User Guide — Module search path
— installed packages, PYTHONPATH, and
--pythonpath. -
Robot Framework 7.4.2 User Guide — Built-in variables
—
${CURDIR},${EXECDIR}, path separators, and temporary directory. - Robot Framework 7.4.2 User Guide — Handling keywords with same names — scope priority, explicit qualification, and search order.
- Robot Framework 7.4.2 User Guide — Libdoc — library/resource documentation and import verification.
- Robot Framework 7.4.2 on PyPI — pinned stable package metadata and Python requirement.
- Robot Framework releases — re-check stable/pre-release status when updating the chapter.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.