def test_prepare_scheduler(): # A core with no services. def create_services(bootstrap_options, legacy_graph_scheduler): return PantsServices() core = PantsDaemonCore(create_services) first_scheduler = core.prepare_scheduler(create_options_bootstrapper(args=["-ldebug"])) second_scheduler = core.prepare_scheduler(create_options_bootstrapper(args=["-lwarn"])) assert first_scheduler is not second_scheduler
def test_prepare_scheduler(): # A core with no services. def create_services(bootstrap_options, legacy_graph_scheduler): return PantsServices() core = PantsDaemonCore(create_options_bootstrapper([]), PyExecutor(2, 4), create_services) first_scheduler, first_options_initializer = core.prepare( create_options_bootstrapper(["-ldebug"])) second_scheduler, second_options_initializer = core.prepare( create_options_bootstrapper(["-lwarn"])) assert first_scheduler is not second_scheduler assert first_options_initializer is second_options_initializer
def test_filter_targets(rule_runner: RuleRunner) -> None: class MockTarget(Target): alias = "target" core_fields = (Sources, ) class MockTargetWithNoSourcesField(Target): alias = "no_sources" core_fields = () rule_runner.create_file("f1.txt") valid_tgt = MockTarget({Sources.alias: ["f1.txt"]}, address=Address("", target_name="valid")) empty_tgt = MockTarget({}, address=Address("", target_name="empty")) invalid_tgt = MockTargetWithNoSourcesField({}, address=Address( "", target_name="invalid")) result = rule_runner.request_product( TargetsWithSources, [ TargetsWithSourcesRequest([valid_tgt, empty_tgt, invalid_tgt]), create_options_bootstrapper(), ], ) assert tuple(result) == (valid_tgt, )
def test_filter_field_sets(rule_runner: RuleRunner) -> None: @dataclass(frozen=True) class MockFieldSet(FieldSet): sources: Sources # Another field to demo that we will preserve the whole FieldSet data structure. tags: Tags rule_runner.create_file("f1.txt") valid_addr = Address("", target_name="valid") valid_field_set = MockFieldSet(valid_addr, Sources(["f1.txt"], address=valid_addr), Tags(None, address=valid_addr)) empty_addr = Address("", target_name="empty") empty_field_set = MockFieldSet(empty_addr, Sources(None, address=empty_addr), Tags(None, address=empty_addr)) result = rule_runner.request_product( FieldSetsWithSources, [ FieldSetsWithSourcesRequest([valid_field_set, empty_field_set]), create_options_bootstrapper(), ], ) assert tuple(result) == (valid_field_set, )
def test_map_third_party_modules_to_addresses(self) -> None: self.add_to_build_file( "3rdparty/python", dedent("""\ python_requirement_library( name='ansicolors', requirements=['ansicolors==1.21'], module_mapping={'ansicolors': ['colors']}, ) python_requirement_library( name='req1', requirements=['req1', 'two_owners'], ) python_requirement_library( name='un_normalized', requirements=['Un-Normalized-Project>3', 'two_owners'], ) """), ) result = self.request_product(ThirdPartyModuleToAddressMapping, [create_options_bootstrapper()]) assert result.mapping == FrozenDict({ "colors": Address.parse("3rdparty/python:ansicolors"), "req1": Address.parse("3rdparty/python:req1"), "un_normalized_project": Address.parse("3rdparty/python:un_normalized"), })
def run_docformatter( self, targets: List[Target], *, passthrough_args: Optional[str] = None, skip: bool = False ) -> Tuple[Sequence[LintResult], FmtResult]: args = ["--backend-packages=pants.backend.python.lint.docformatter"] if passthrough_args: args.append(f"--docformatter-args='{passthrough_args}'") if skip: args.append("--docformatter-skip") options_bootstrapper = create_options_bootstrapper(args=args) field_sets = [DocformatterFieldSet.create(tgt) for tgt in targets] lint_results = self.request_product( LintResults, [DocformatterRequest(field_sets), options_bootstrapper] ) input_sources = self.request_product( SourceFiles, [ SourceFilesRequest(field_set.sources for field_set in field_sets), options_bootstrapper, ], ) fmt_result = self.request_product( FmtResult, [ DocformatterRequest(field_sets, prior_formatter_result=input_sources.snapshot), options_bootstrapper, ], ) return lint_results.results, fmt_result
def run_pylint( self, targets: List[Target], *, config: Optional[str] = None, passthrough_args: Optional[str] = None, skip: bool = False, additional_args: Optional[List[str]] = None, ) -> Sequence[LintResult]: args = list(self.global_args) if config: self.create_file(relpath="pylintrc", contents=config) args.append("--pylint-config=pylintrc") if passthrough_args: args.append(f"--pylint-args='{passthrough_args}'") if skip: args.append("--pylint-skip") if additional_args: args.extend(additional_args) results = self.request_product( LintResults, [ PylintRequest(PylintFieldSet.create(tgt) for tgt in targets), create_options_bootstrapper(args=args), ], ) return results.results
def run_flake8( self, targets: List[Target], *, config: Optional[str] = None, passthrough_args: Optional[str] = None, skip: bool = False, additional_args: Optional[List[str]] = None, ) -> Sequence[LintResult]: args = ["--backend-packages=pants.backend.python.lint.flake8"] if config: self.create_file(relpath=".flake8", contents=config) args.append("--flake8-config=.flake8") if passthrough_args: args.append(f"--flake8-args='{passthrough_args}'") if skip: args.append("--flake8-skip") if additional_args: args.extend(additional_args) results = self.request_product( LintResults, [ Flake8Request(Flake8FieldSet.create(tgt) for tgt in targets), create_options_bootstrapper(args=args), ], ) return results.results
def test_target_adaptor_parsed_correctly( target_adaptor_rule_runner: RuleRunner) -> None: target_adaptor_rule_runner.add_to_build_file( "helloworld", dedent("""\ mock_tgt( fake_field=42, dependencies=[ # Because we don't follow dependencies or even parse dependencies, this # self-cycle should be fine. "helloworld", ":sibling", "helloworld/util", "helloworld/util:tests", ], ) """), ) addr = Address("helloworld") target_adaptor = target_adaptor_rule_runner.request_product( TargetAdaptor, [addr, create_options_bootstrapper()]) assert target_adaptor.name == "helloworld" assert target_adaptor.type_alias == "mock_tgt" assert target_adaptor.kwargs["dependencies"] == [ "helloworld", ":sibling", "helloworld/util", "helloworld/util:tests", ] # NB: TargetAdaptors do not validate what fields are valid. The Target API should error # when encountering this, but it's fine at this stage. assert target_adaptor.kwargs["fake_field"] == 42
def test_line_oriented_goal() -> None: class OutputtingGoalOptions(LineOriented, GoalSubsystem): name = "dummy" class OutputtingGoal(Goal): subsystem_cls = OutputtingGoalOptions @goal_rule def output_rule(console: Console, options: OutputtingGoalOptions) -> OutputtingGoal: with options.output(console) as write_stdout: write_stdout("output...") with options.line_oriented(console) as print_stdout: print_stdout("line oriented") return OutputtingGoal(0) with mock_console(create_options_bootstrapper()) as (console, stdio_reader): result: OutputtingGoal = run_rule_with_mocks( output_rule, rule_args=[ console, create_goal_subsystem(OutputtingGoalOptions, sep="\\n", output_file=None), ], ) assert result.exit_code == 0 assert stdio_reader.get_stdout() == "output...line oriented\n"
def test_context_object_on_streaming_workunits( rule_runner: RuleRunner, run_tracker: RunTracker) -> None: scheduler = rule_runner.scheduler def callback(**kwargs) -> None: context = kwargs["context"] assert isinstance(context, StreamingWorkunitContext) completed_workunits = kwargs["completed_workunits"] for workunit in completed_workunits: if "artifacts" in workunit and "stdout_digest" in workunit[ "artifacts"]: digest = workunit["artifacts"]["stdout_digest"] output = context.single_file_digests_to_bytes([digest]) assert output == (b"stdout output\n", ) handler = StreamingWorkunitHandler( scheduler, run_tracker=run_tracker, callbacks=[callback], report_interval_seconds=0.01, max_workunit_verbosity=LogLevel.INFO, specs=Specs.empty(), options_bootstrapper=create_options_bootstrapper([]), ) stdout_process = Process(argv=("/bin/bash", "-c", "/bin/echo 'stdout output'"), description="Stdout process") with handler.session(): rule_runner.request(ProcessResult, [stdout_process])
def assert_injected( self, *, source_roots: List[str], original_declared_files: List[str], original_undeclared_files: List[str], expected_discovered: List[str], ) -> None: for f in original_undeclared_files: self.create_file(f, "# undeclared") request = AncestorFilesRequest( "__init__.py", self.make_snapshot({fp: "# declared" for fp in original_declared_files}), ) bootstrapper = create_options_bootstrapper(args=[f"--source-root-patterns={source_roots}"]) result = self.request_product(AncestorFiles, [request, bootstrapper]).snapshot assert list(result.files) == sorted(expected_discovered) materialized_result = self.request_product(DigestContents, [result.digest]) for file_content in materialized_result: path = file_content.path if not path.endswith("__init__.py"): continue assert path in original_declared_files or path in expected_discovered expected = b"# declared" if path in original_declared_files else b"# undeclared" assert file_content.content == expected
def run_goal( targets: Sequence[Target], *, target_type: list[str] | None = None, address_regex: list[str] | None = None, tag_regex: list[str] | None = None, granularity: TargetGranularity | None = None, ) -> str: with mock_console(create_options_bootstrapper()) as (console, stdio_reader): run_rule_with_mocks( filter_targets, rule_args=[ Targets(targets), create_goal_subsystem( FilterSubsystem, sep="\\n", output_file=None, target_type=target_type or [], address_regex=address_regex or [], tag_regex=tag_regex or [], granularity=granularity or TargetGranularity.all_targets, # Deprecated. type=[], target=[], regex=[], ancestor=[], ), console, RegisteredTargetTypes.create({type(tgt) for tgt in targets}), ], ) assert not stdio_reader.get_stderr() return stdio_reader.get_stdout()
def test_run_information(exit_code, expected, **kwargs) -> None: with temporary_dir() as buildroot: with environment_as(PANTS_BUILDROOT_OVERRIDE=buildroot): run_tracker = RunTracker( create_options_bootstrapper([]).bootstrap_options) specs = ["src/python/pants/goal/run_tracker_test.py"] run_tracker.start(run_start_time=time.time(), specs=specs) run_information = run_tracker.run_information() assert run_information["buildroot"] == get_buildroot() assert run_information["path"] == get_buildroot() # freezegun doesn't seem to accurately mock the time zone, # (i.e. the time zone used depends on that of the machine that # executes the test), so we can only safely assert that the # month and year appear in the human-readable string contained # in the "datetime" key assert "Jan" in run_information["datetime"] assert "2020" in run_information["datetime"] assert run_information["timestamp"] == 1578657601.0 assert run_information["user"] == getpass.getuser() assert run_information["version"] == VERSION assert re.match("pants.*run_tracker_test.py", run_information["cmd_line"]) assert run_information["specs_from_command_line"] == [ "src/python/pants/goal/run_tracker_test.py" ] frozen_time = kwargs["frozen_time"] frozen_time.tick(delta=datetime.timedelta(seconds=1)) run_tracker.end_run(exit_code) run_information_after_ended = run_tracker.run_information() assert run_information_after_ended["outcome"] == expected
def test_run_information(exit_code: ExitCode, expected: str, tmp_path: Path, **kwargs) -> None: frozen_time = kwargs["frozen_time"] buildroot = tmp_path.as_posix() with environment_as(PANTS_BUILDROOT_OVERRIDE=buildroot): spec = "test/example.py" ob = create_options_bootstrapper(["list", spec]) run_tracker = RunTracker(ob.args, ob.bootstrap_options) specs = [spec] run_tracker.start(run_start_time=time.time(), specs=specs) run_information = run_tracker.run_information() assert run_information["buildroot"] == get_buildroot() assert run_information["path"] == get_buildroot() # freezegun doesn't seem to accurately mock the time zone, # (i.e. the time zone used depends on that of the machine that # executes the test), so we can only safely assert that the # month and year appear in the human-readable string contained # in the "datetime" key assert "Jan" in run_information["datetime"] assert "2020" in run_information["datetime"] assert run_information["timestamp"] == 1578657601.0 assert run_information["user"] == getpass.getuser() assert run_information["version"] == VERSION assert re.match(f"pants.*{spec}", run_information["cmd_line"]) assert run_information["specs_from_command_line"] == [spec] frozen_time.tick(delta=datetime.timedelta(seconds=1)) run_tracker.end_run(exit_code) run_information_after_ended = run_tracker.run_information() assert run_information_after_ended["outcome"] == expected
def run_typecheck_rule( *, request_types: Sequence[Type[CheckRequest]], targets: list[Target], only: list[str] | None = None, ) -> Tuple[int, str]: union_membership = UnionMembership({CheckRequest: request_types}) check_subsystem = create_subsystem(CheckSubsystem, only=only or []) with mock_console(create_options_bootstrapper()) as (console, stdio_reader): rule_runner = RuleRunner() result: Check = run_rule_with_mocks( check, rule_args=[ console, Workspace(rule_runner.scheduler, _enforce_effects=False), Targets(targets), DistDir(relpath=Path("dist")), union_membership, check_subsystem, ], mock_gets=[ MockGet( output_type=CheckResults, input_type=CheckRequest, mock=lambda field_set_collection: field_set_collection.check_results, ), ], union_membership=union_membership, ) assert not stdio_reader.get_stdout() return result.exit_code, stdio_reader.get_stderr()
def test_streaming_workunits_expanded_specs(run_tracker: RunTracker) -> None: rule_runner = RuleRunner( target_types=[PythonLibrary], rules=[ QueryRule(ProcessResult, (Process,)), ], ) rule_runner.set_options(["--backend-packages=pants.backend.python"]) rule_runner.create_file("src/python/somefiles/BUILD", "python_library()") rule_runner.create_file("src/python/somefiles/a.py", "print('')") rule_runner.create_file("src/python/somefiles/b.py", "print('')") rule_runner.create_file("src/python/others/BUILD", "python_library()") rule_runner.create_file("src/python/others/a.py", "print('')") rule_runner.create_file("src/python/others/b.py", "print('')") specs = SpecsParser(get_buildroot()).parse_specs( ["src/python/somefiles::", "src/python/others/b.py"] ) class Callback(WorkunitsCallback): @property def can_finish_async(self) -> bool: return False def __call__(self, **kwargs) -> None: context = kwargs["context"] assert isinstance(context, StreamingWorkunitContext) expanded = context.get_expanded_specs() targets = expanded.targets assert len(targets.keys()) == 2 assert targets["src/python/others/b.py"] == [ TargetInfo(filename="src/python/others/b.py") ] assert set(targets["src/python/somefiles"]) == { TargetInfo(filename="src/python/somefiles/a.py"), TargetInfo(filename="src/python/somefiles/b.py"), } handler = StreamingWorkunitHandler( scheduler=rule_runner.scheduler, run_tracker=run_tracker, callbacks=[Callback()], report_interval_seconds=0.01, max_workunit_verbosity=LogLevel.INFO, specs=specs, options_bootstrapper=create_options_bootstrapper( ["--backend-packages=pants.backend.python"] ), pantsd=False, ) stdout_process = Process( argv=("/bin/bash", "-c", "/bin/echo 'stdout output'"), description="Stdout process" ) with handler: rule_runner.request(ProcessResult, [stdout_process])
def test_log_filtering_by_rule() -> None: with temporary_dir() as tmpdir: ob = create_options_bootstrapper([ f"--pants-workdir={tmpdir}", '--log-levels-by-target={"debug_target": "debug"}' ]) # Do not set up a stdio destination, meaning that all messages will go to the log. global_bootstrap_options = ob.bootstrap_options.for_global_scope() with initialize_stdio(global_bootstrap_options): native_engine.write_log(msg="log msg one", level=LogLevel.INFO.level, target="some.target") native_engine.write_log(msg="log msg two", level=LogLevel.DEBUG.level, target="some.other.target") native_engine.write_log(msg="log msg three", level=LogLevel.DEBUG.level, target="debug_target") loglines = (Path(global_bootstrap_options.pants_workdir, "pants.log").read_text().splitlines()) assert "[INFO] log msg one" in loglines[0] assert "[DEBUG] log msg three" in loglines[1] assert len(loglines) == 2
def create_dynamic_remote_options( *, initial_headers: dict[str, str] | None = None, address: str | None = "grpc://fake.url:10", token_path: str | None = None, plugin: str | None = None, ) -> DynamicRemoteOptions: if initial_headers is None: initial_headers = {} args = [ "--remote-cache-read", f"--remote-execution-address={address}", f"--remote-store-address={address}", f"--remote-store-headers={initial_headers}", f"--remote-execution-headers={initial_headers}", "--remote-instance-name=main", ] if token_path: args.append(f"--remote-oauth-bearer-token-path={token_path}") if plugin: args.append(f"--remote-auth-plugin={plugin}") ob = create_options_bootstrapper(args) env = CompleteEnvironment({}) _build_config, options = OptionsInitializer(ob).build_config_and_options(ob, env, raise_=False) return DynamicRemoteOptions.from_options(options, env)[0]
def run_goal_rule( self, goal: Type[Goal], *, global_args: Optional[Iterable[str]] = None, args: Optional[Iterable[str]] = None, env: Optional[Mapping[str, str]] = None, ) -> GoalRuleResult: options_bootstrapper = create_options_bootstrapper( args=(*(global_args or []), goal.name, *(args or [])), env=env, ) raw_specs = options_bootstrapper.get_full_options([ *GlobalOptions.known_scope_infos(), *goal.subsystem_cls.known_scope_infos() ]).specs specs = SpecsParser(self.build_root).parse_specs(raw_specs) stdout, stderr = StringIO(), StringIO() console = Console(stdout=stdout, stderr=stderr) exit_code = self.scheduler.run_goal_rule( goal, Params( specs, console, options_bootstrapper, Workspace(self.scheduler), InteractiveRunner(self.scheduler), ), ) console.flush() return GoalRuleResult(exit_code, stdout.getvalue(), stderr.getvalue())
def run_mypy( self, targets: List[Target], *, config: Optional[str] = None, passthrough_args: Optional[str] = None, skip: bool = False, additional_args: Optional[List[str]] = None, ) -> Sequence[TypecheckResult]: args = list(self.global_args) if config: self.create_file(relpath="mypy.ini", contents=config) args.append("--mypy-config=mypy.ini") if passthrough_args: args.append(f"--mypy-args='{passthrough_args}'") if skip: args.append("--mypy-skip") if additional_args: args.extend(additional_args) result = self.request_product( TypecheckResults, [ MyPyRequest(MyPyFieldSet.create(tgt) for tgt in targets), create_options_bootstrapper(args=args), ], ) return result.results
def make_target( self, source_files: List[FileContent], *, package: Optional[str] = None, name: str = "target", ) -> Target: if not package: package = self.package for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) source_globs = [ PurePath(source_file.path).name for source_file in source_files ] self.add_to_build_file( f"{package}", dedent(f"""\ python_library( name={repr(name)}, sources={source_globs}, ) """), ) return self.request_product( WrappedTarget, [ Address(package, target_name=name), create_options_bootstrapper(args=self.global_args), ], ).target
def test_anonymous_telemetry_with_no_repo_id() -> None: with temporary_dir() as buildroot: with environment_as(PANTS_BUILDROOT_OVERRIDE=buildroot): opts = create_options_bootstrapper([]).bootstrap_options run_tracker = RunTracker(opts) run_tracker.start(run_start_time=time.time(), specs=[]) run_tracker.end_run(PANTS_SUCCEEDED_EXIT_CODE) repo_id = "" telemetry = run_tracker.get_anonymous_telemetry_data(repo_id) # Check that these keys have non-trivial values. for key in ( "run_id", "timestamp", "duration", "outcome", "platform", "python_implementation", "python_version", "pants_version", ): assert bool(telemetry.get(key)) for key in ("repo_id", "machine_id", "user_id"): assert telemetry.get(key) == ""
def set_options( self, args: Iterable[str], *, env: Mapping[str, str] | None = None, env_inherit: set[str] | None = None, ) -> None: """Update the engine session with new options and/or environment variables. The environment variables will be used to set the `CompleteEnvironment`, which is the environment variables captured by the parent Pants process. Some rules use this to be able to read arbitrary env vars. Any options that start with `PANTS_` will also be used to set options. Environment variables listed in `env_inherit` and not in `env` will be inherited from the test runner's environment (os.environ) This will override any previously configured values. """ env = { **{ k: os.environ[k] for k in (env_inherit or set()) if k in os.environ }, **(env or {}), } self.options_bootstrapper = create_options_bootstrapper(args=args, env=env) self.environment = CompleteEnvironment(env) self._set_new_session(self.scheduler.scheduler)
def test_source_roots_request() -> None: rule_runner = RuleRunner(rules=[ *source_root_rules(), QueryRule(SourceRootsResult, (SourceRootsRequest, OptionsBootstrapper)), ]) req = SourceRootsRequest( files=(PurePath("src/python/foo/bar.py"), PurePath("tests/python/foo/bar_test.py")), dirs=(PurePath("src/python/foo"), PurePath("src/python/baz/qux")), ) res = rule_runner.request_product( SourceRootsResult, [ req, create_options_bootstrapper( args=["--source-root-patterns=['src/python','tests/python']"]), ], ) assert { PurePath("src/python/foo/bar.py"): SourceRoot("src/python"), PurePath("tests/python/foo/bar_test.py"): SourceRoot("tests/python"), PurePath("src/python/foo"): SourceRoot("src/python"), PurePath("src/python/baz/qux"): SourceRoot("src/python"), } == dict(res.path_to_root)
def run_goal(targets: list[MockTarget], *, show_documented: bool = False) -> tuple[str, str]: with mock_console(create_options_bootstrapper()) as (console, stdio_reader): run_rule_with_mocks( list_targets, rule_args=[ Addresses(tgt.address for tgt in targets), create_goal_subsystem( ListSubsystem, sep="\\n", output_file=None, documented=show_documented, ), console, ], mock_gets=[ MockGet( output_type=UnexpandedTargets, input_type=Addresses, mock=lambda _: UnexpandedTargets(targets), ) ], ) return stdio_reader.get_stdout(), stdio_reader.get_stderr()
def create_execution_options( *, initial_headers: dict[str, str], token_path: str | None = None, plugin: str | None = None, remote_store_address: str = "grpc://fake.url:10", remote_execution_address: str = "grpc://fake.url:10", local_only: bool = False, ) -> ExecutionOptions: args = [ "--remote-cache-read", f"--remote-execution-address={remote_execution_address}", f"--remote-store-address={remote_store_address}", f"--remote-store-headers={initial_headers}", f"--remote-execution-headers={initial_headers}", "--remote-instance-name=main", ] if token_path: args.append(f"--remote-oauth-bearer-token-path={token_path}") if plugin: args.append(f"--remote-auth-plugin={plugin}") ob = create_options_bootstrapper(args) env = CompleteEnvironment({}) _build_config, options = OptionsInitializer( ob, env).build_config_and_options(ob, env, raise_=False) return ExecutionOptions.from_options(options, env, local_only=local_only)
def run_typecheck_rule( *, request_types: List[Type[TypecheckRequest]], targets: List[Target], include_sources: bool = True, ) -> Tuple[int, str]: union_membership = UnionMembership({TypecheckRequest: request_types}) with mock_console(create_options_bootstrapper()) as (console, stdio_reader): result: Typecheck = run_rule_with_mocks( typecheck, rule_args=[console, Targets(targets), union_membership], mock_gets=[ MockGet( output_type=EnrichedTypecheckResults, input_type=TypecheckRequest, mock=lambda field_set_collection: field_set_collection. typecheck_results, ), MockGet( output_type=FieldSetsWithSources, input_type=FieldSetsWithSourcesRequest, mock=lambda field_sets: FieldSetsWithSources( field_sets if include_sources else ()), ), ], union_membership=union_membership, ) assert not stdio_reader.get_stdout() return result.exit_code, stdio_reader.get_stderr()
def test_options_parse_memoization(self): # Confirm that re-executing with a new-but-identical Options object results in memoization. def parse(ob): return self.request_product(ScopedOptions, [Scope(GLOBAL_SCOPE), ob]) # If two OptionsBootstrapper instances are not equal, memoization will definitely not kick in. one_opts = create_options_bootstrapper() two_opts = create_options_bootstrapper() self.assertEqual(one_opts, two_opts) self.assertEqual(hash(one_opts), hash(two_opts)) # If they are equal, executing parsing on them should result in a memoized object. one = parse(one_opts) two = parse(two_opts) self.assertEqual(one, two) self.assertIs(one, two)
def test_more_complicated_engine_aware(rule_runner: RuleRunner, run_tracker: RunTracker) -> None: tracker = WorkunitTracker() handler = StreamingWorkunitHandler( rule_runner.scheduler, run_tracker=run_tracker, callbacks=[tracker.add], report_interval_seconds=0.01, max_workunit_verbosity=LogLevel.TRACE, specs=Specs.empty(), options_bootstrapper=create_options_bootstrapper([]), ) with handler.session(): input_1 = CreateDigest(( FileContent(path="a.txt", content=b"alpha"), FileContent(path="b.txt", content=b"beta"), )) digest_1 = rule_runner.request(Digest, [input_1]) snapshot_1 = rule_runner.request(Snapshot, [digest_1]) input_2 = CreateDigest((FileContent(path="g.txt", content=b"gamma"), )) digest_2 = rule_runner.request(Digest, [input_2]) snapshot_2 = rule_runner.request(Snapshot, [digest_2]) input = ComplicatedInput(snapshot_1=snapshot_1, snapshot_2=snapshot_2) rule_runner.request(Output, [input]) finished = list( itertools.chain.from_iterable(tracker.finished_workunit_chunks)) workunit = next( item for item in finished if item["name"] == "pants.engine.internals.engine_test.a_rule") streaming_workunit_context = handler._context artifacts = workunit["artifacts"] output_snapshot_1 = artifacts["snapshot_1"] output_snapshot_2 = artifacts["snapshot_2"] output_contents_list = streaming_workunit_context.snapshots_to_file_contents( [output_snapshot_1, output_snapshot_2]) assert len(output_contents_list) == 2 assert isinstance(output_contents_list[0], DigestContents) assert isinstance(output_contents_list[1], DigestContents) digest_contents_1 = output_contents_list[0] digest_contents_2 = output_contents_list[1] assert len(tuple(x for x in digest_contents_1 if x.content == b"alpha")) == 1 assert len(tuple(x for x in digest_contents_1 if x.content == b"beta")) == 1 assert len(tuple(x for x in digest_contents_2 if x.content == b"gamma")) == 1