Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plain2code.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ def main(): # noqa: C901
codeplainAPI = codeplain_api.CodeplainAPI(args.api_key, console)
codeplainAPI.api_url = args.api

run_state = RunState(spec_filename=args.filename, replay_with=args.replay_with)
run_state = RunState(spec_filename=args.filename, replay_with=args.replay_with, job_tag=args.job_tag)

# Without a terminal nobody can watch or drive the TUI, so render as --headless does:
# progress on stdout, and a non-zero exit status when the render stops.
Expand Down
30 changes: 30 additions & 0 deletions plain2code_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
DEFAULT_BUILD_FOLDER = "plain_modules"
DEFAULT_BUILD_DEST = "dist"
DEFAULT_CONFORMANCE_TESTS_DEST = "dist_conformance_tests"
MAX_JOB_TAG_LENGTH = 300

UNIT_TESTS_SCRIPT_NAME = "unittests_script"
CONFORMANCE_TESTS_SCRIPT_NAME = "conformance_tests_script"
Expand Down Expand Up @@ -76,6 +77,15 @@ def non_empty_string(s):
return s


def job_tag_string(s):
s = str(s)
if not s:
raise argparse.ArgumentTypeError("The job tag cannot be empty.")
if len(s) > MAX_JOB_TAG_LENGTH:
raise argparse.ArgumentTypeError(f"The job tag cannot be longer than {MAX_JOB_TAG_LENGTH} characters.")
return s


def frid_string(s):
"""Validate that the FRID is an integer."""
if not s:
Expand Down Expand Up @@ -363,6 +373,15 @@ def create_parser():
help="",
)

_add_arg(
parser,
"--job-tag",
type=job_tag_string,
default=None,
help=f"Tag sent to the server with every request and attached to the render's LangSmith traces "
Comment thread
VitjanZ marked this conversation as resolved.
Resolved
f"(max {MAX_JOB_TAG_LENGTH} characters).",
)

_add_arg(
parser,
"--template-dir",
Expand Down Expand Up @@ -450,6 +469,15 @@ def create_parser():
return parser


def _validate_job_tag(args, parser):
# Values from config.yaml bypass argparse's type conversion, so validate them here.
if args.job_tag is not None:
try:
args.job_tag = job_tag_string(args.job_tag)
except argparse.ArgumentTypeError as e:
parser.error(f"--job-tag: {e}")


def parse_arguments(command_line: Optional[Sequence[str]] = None):
parser = create_parser()

Expand Down Expand Up @@ -496,6 +524,8 @@ def parse_arguments(command_line: Optional[Sequence[str]] = None):
if not args.log_to_file and args.argument_sources.get("log_file_name") != "default":
parser.error("--log-file-name cannot be used when --log-to-file is False.")

_validate_job_tag(args, parser)

if args.full_plain and args.dry_run:
parser.error("--full-plain and --dry-run are mutually exclusive")

Expand Down
8 changes: 6 additions & 2 deletions plain2code_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class RunState:
"""Contains information about the identifiable state of the rendering process."""

def __init__(self, spec_filename: str, replay_with: Optional[str] = None):
def __init__(self, spec_filename: str, replay_with: Optional[str] = None, job_tag: Optional[str] = None):
self.replay: bool = replay_with is not None
self.render_succeeded: bool = False
self.render_cancelled: bool = False
Expand All @@ -19,6 +19,7 @@ def __init__(self, spec_filename: str, replay_with: Optional[str] = None):
else:
self.render_id: str = str(uuid.uuid4())
self.spec_filename: str = spec_filename
self.job_tag: Optional[str] = job_tag
self.call_count: int = 0
self.unittest_batch_id: int = 0
self.render_time_accumulated: int = 0
Expand Down Expand Up @@ -70,9 +71,12 @@ def set_last_render_start_timestamp(self):
self.last_render_start_timestamp = time.monotonic()

def to_dict(self):
return {
state = {
"render_id": self.render_id,
"call_count": self.call_count,
"replay": self.replay,
"spec_filename": self.spec_filename,
}
if self.job_tag is not None:
state["job_tag"] = self.job_tag
return state
20 changes: 20 additions & 0 deletions tests/test_arg_provenance.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,23 @@ def test_mixed_sources(project):
assert srcs["conformance_tests_dest"] == "cli"
assert srcs["build_folder"] == "config"
assert srcs["build_dest"] == "default"


def test_job_tag_from_cli_and_config(project):
plain_file = os.path.join(project, "module.plain")
assert parse_arguments([plain_file]).job_tag is None
assert parse_arguments([plain_file, "--job-tag", "nightly"]).job_tag == "nightly"

(Path(project) / "config.yaml").write_text("job-tag: 123\n")
assert parse_arguments([plain_file]).job_tag == "123"
assert parse_arguments([plain_file, "--job-tag", "from_cli"]).job_tag == "from_cli"


def test_job_tag_too_long_is_rejected(project):
plain_file = os.path.join(project, "module.plain")
with pytest.raises(SystemExit):
parse_arguments([plain_file, "--job-tag", "x" * 301])

(Path(project) / "config.yaml").write_text(f"job-tag: {'x' * 301}\n")
with pytest.raises(SystemExit):
parse_arguments([plain_file])
5 changes: 5 additions & 0 deletions tests/test_plain2code_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ def test_add_to_render_time_is_cumulative_across_segments():
run_state.add_to_render_time()

assert run_state.render_time_accumulated == 7


def test_to_dict_includes_job_tag_only_when_set():
assert "job_tag" not in RunState(spec_filename="x.plain").to_dict()
assert RunState(spec_filename="x.plain", job_tag="nightly").to_dict()["job_tag"] == "nightly"
1 change: 1 addition & 0 deletions tests/test_render_finished_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def make_args(api_key="test-key", headless=False):
render_from=None,
headless=headless,
replay_with=None,
job_tag=None,
log_to_file=False,
log_file_name="codeplain.log",
conformance_tests_script=None,
Expand Down
1 change: 1 addition & 0 deletions tests/test_terminal_attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def make_args():
force_render=False,
headless=False,
replay_with=None,
job_tag=None,
log_to_file=False,
log_file_name="codeplain.log",
render_conformance_tests=False,
Expand Down
Loading