Implementation:MarketSquare Robotframework browser Inv Build
Document Type
API Doc -- Documents the Invoke build tasks that constitute the project's multi-stage build pipeline, including dependency installation, protobuf compilation, Node.js compilation, test app building, and type stub generation.
API Summary
The build task is the top-level entry point that orchestrates the full build pipeline through Invoke's task dependency system. It depends on deps, protobuf, node_build, and create_test_app.
Source References
| File | Lines | Description |
|---|---|---|
tasks.py |
L287-289 | build task (top-level)
|
tasks.py |
L114-158 | deps task (dependency installation)
|
tasks.py |
L206-264 | protobuf task and helpers
|
tasks.py |
L274-279 | node_build task
|
tasks.py |
L282-284 | create_test_app task
|
tasks.py |
L267-271 | _gen_stub helper function
|
CLI Usage
inv build
This single command runs the entire build pipeline in dependency order.
Task: build
@task(deps, protobuf, node_build, create_test_app)
def build(c: Context):
_gen_stub(c)
Parameters:
c(Context) -- Invoke execution context
Dependencies: deps, protobuf, node_build, create_test_app (run in dependency order)
Behavior:
After all dependencies complete, calls _gen_stub(c) to regenerate Python type stubs. This ensures stubs reflect any changes from the build process.
Task: deps
@task
def deps(c, system=False, force=False, uv=False):
"""Install dependencies for development."""
CLI: inv deps, inv deps --force, inv deps --system
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
system |
bool | False | Install to system Python instead of virtualenv |
force |
bool | False | Force npm install even if package-lock.json unchanged |
uv |
bool | False | Skip pip install step (assumes uv is already available) |
Behavior:
- Checks if pip is available; if not, sets
uv=True - Unless
uv=True, upgrades pip and installs uv - Installs dev dependencies:
uv pip install -r Browser/dev-requirements.txt - Installs project dependencies:
uv pip install -r pyproject.toml - In CI (
GITHUB_WORKFLOWset): adds--pythonflag and cleans node_modules - Checks if
package-lock.jsonchanged; if so, runsnpm installandnpx playwright install --with-deps
Task: protobuf
@task
def protobuf(c, force=False):
"""Compile grpc protobuf files."""
CLI: inv protobuf, inv protobuf --force
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
force |
bool | False | Force protobuf compilation even if .proto files unchanged |
Behavior:
- Creates output directories if they do not exist:
Browser/generated/andnode/playwright-wrapper/generated/ - Creates
__init__.pyin the Python protobuf directory - Checks if
.protofiles have changed since last generation - If changed (or forced), runs both Python and Node.js protobuf generation
Python protobuf generation:
def _python_protobuf_gen(c):
c.run(
f"python -m grpc_tools.protoc -I protobuf "
f"--python_out=Browser/generated "
f"--grpc_python_out={python_protobuf_dir} "
f"--mypy_out={python_protobuf_dir} protobuf/*.proto"
)
After generation, it fixes the import path in playwright_pb2_grpc.py to use the absolute import from Browser.generated import playwright_pb2.
Node.js protobuf generation:
def _node_protobuf_gen(c):
# First pass: JavaScript + gRPC stubs
cmd = (
"npm run grpc_tools_node_protoc -- "
f"--js_out=import_style=commonjs,binary:{node_protobuf_dir} "
f"--grpc_out=grpc_js:{node_protobuf_dir} "
f"--plugin=protoc-gen-grpc={protoc_plugin} "
"-I ./protobuf protobuf/*.proto"
)
# Second pass: TypeScript definitions
cmd = (
"npm run grpc_tools_node_protoc -- "
f"--plugin=protoc-gen-ts={protoc_ts_plugin} "
f"--ts_out={node_protobuf_dir} "
"-I ./protobuf protobuf/*.proto"
)
Task: node_build
@task(protobuf)
def node_build(c: Context):
c.run("npm run build")
shutil.rmtree(WRAPPER_DIR / "static", ignore_errors=True)
shutil.copytree(node_dir / "playwright-wrapper" / "static", WRAPPER_DIR / "static")
_gen_stub(c)
CLI: inv node-build
Dependencies: protobuf (must complete first)
Behavior:
- Runs
npm run build-- triggers esbuild to compile TypeScript and bundle intoBrowser/wrapper/index.js - Removes and re-copies the
static/directory from the Node.js source toBrowser/wrapper/static/ - Generates Python type stubs via
_gen_stub
Task: create_test_app
@task
def create_test_app(c):
c.run("npm run build-test-app")
CLI: inv create-test-app
Behavior:
Runs npm run build-test-app to compile the dynamic test application used by acceptance tests.
Helper: _gen_stub
def _gen_stub(c: Context):
shutil.rmtree("mypy_stub/", ignore_errors=True)
Path("Browser/browser.pyi").unlink(missing_ok=True)
c.run("stubgen --output mypy_stub Browser")
c.run("python -m Browser.gen_stub")
Behavior:
- Cleans previous stub outputs (
mypy_stub/directory andBrowser/browser.pyi) - Runs
stubgento generate raw stubs from the Browser package - Runs
Browser.gen_stubmodule to post-process stubs into the finalbrowser.pyi
Build Outputs
| Output | Produced By | Description |
|---|---|---|
Browser/generated/playwright_pb2.py |
protobuf | Python protobuf message classes |
Browser/generated/playwright_pb2_grpc.py |
protobuf | Python gRPC client/server stubs |
Browser/generated/playwright_pb2.pyi |
protobuf | MyPy type stubs for protobuf |
node/playwright-wrapper/generated/*.js |
protobuf | Node.js protobuf stubs |
node/playwright-wrapper/generated/*.ts |
protobuf | TypeScript definitions for protobuf |
Browser/wrapper/index.js |
node_build | Bundled Playwright wrapper |
Browser/wrapper/static/ |
node_build | Static files for the wrapper |
Browser/browser.pyi |
_gen_stub | Python type stubs for IDE support |
Incremental Build
The _sources_changed helper enables incremental builds:
def _sources_changed(source_files: Iterable[Path], timestamp_file: Path):
if timestamp_file.exists():
last_built = timestamp_file.lstat().st_mtime
src_last_modified = [f.lstat().st_mtime for f in source_files]
return not all(last_built >= modified for modified in src_last_modified)
return True
Used by both deps (checking package-lock.json) and protobuf (checking .proto files).
Related
- MarketSquare_Robotframework_browser_Project_Build_Pipeline -- Principle document for the build pipeline
- MarketSquare_Robotframework_browser_Bootstrap_Script -- Environment setup before building
- MarketSquare_Robotframework_browser_Inv_Utest_Atest -- Running tests after building
- MarketSquare_Robotframework_browser_Inv_Lint -- Code quality checks