I have code that calls into the engine via `Schedu...
# development
f
I have code that calls into the engine via
SchedulerSession.execute
. I am getting this error:
Copy code
E       ValueError: Encountered 2 rule graph errors:
E         No installed rules return the type UnionMembership, and it was not provided by potential callers of @rule(pants.bsp.rules:54:bsp_workspace_build_targets(WorkspaceBuildTargetsParams, UnionMembership) -> WorkspaceBuildTargetsResult).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.
E         No installed rules return the type WorkspaceBuildTargetsParams, and it was not provided by potential callers of @rule(pants.bsp.rules:54:bsp_workspace_build_targets(WorkspaceBuildTargetsParams, UnionMembership) -> WorkspaceBuildTargetsResult).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.
does the call to
execute
need to provide a
UnionMembership
as an additional “subject” parameter?
Or does it just need a
QueryRule
?
c
The latter, would be my guess..
w
both… needs a
QueryRule
the declares that the
UnionMembership
comes in
…and then when actually executing, needs to provide the
UnionMembership
.
a
QueryRule
is: “expect calls to
scheduler.execute
with these input types for this output type”
in production
@goal_rules
though, the
UnionMembership
is a singleton (here)
f
even with the QueryRule and requesting
UnionMembership
first, I still get rule graph error:
Copy code
E       ValueError: Encountered 3 rule graph errors:
E         No installed rules return the type UnionMembership, and it was not provided by potential callers of @rule(pants.bsp.rules:54:bsp_workspace_build_targets(WorkspaceBuildTargetsParams, UnionMembership) -> WorkspaceBuildTargetsResult).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.
E         No installed rules return the type UnionMembership, and it was not provided by potential callers of Query(UnionMembership for ()).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.
E         No installed rules return the type WorkspaceBuildTargetsParams, and it was not provided by potential callers of @rule(pants.bsp.rules:54:bsp_workspace_build_targets(WorkspaceBuildTargetsParams, UnionMembership) -> WorkspaceBuildTargetsResult).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.
w
@fast-nail-55400: all this to say: if you are using the Scheduler given to your BuiltinGoal, you shouldn’t have to worry about this, because that Scheduler should already have a singleton for the UnionMembership installed.
f
I am using a
SchedulerSession
allocated via
new_session
.
(which has been a code review comment to do that to ensure UI is isolated or something like that)
w
that error is from rule graph “compile” time, before you actually make your requests
what is the stack that is actually failing to create a Scheduler?
i.e., what is the rest of the traceback above that
ValueError
f
Copy code
def test_errors_for_uninitialized_connection(self, tmp_path: Path) -> None:
        with setup_pipes() as pipes:
            # TODO: This code should be moved to a context manager. For now, only the pipes are managed
            # with a context manager.
>           scheduler = self.mk_scheduler(tmp_path, [*bsp_rules()])

src/python/pants/bsp/protocol_test.py:66:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/python/pants/engine/internals/scheduler_test_base.py:48: in mk_scheduler
    include_trace_on_error=include_trace_on_error,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <pants.engine.internals.scheduler.Scheduler object at 0x1101ca390>

    def __init__(
        self,
        *,
        ignore_patterns: list[str],
        use_gitignore: bool,
        build_root: str,
        local_execution_root_dir: str,
        named_caches_dir: str,
        ca_certs_path: str | None,
        rules: Iterable[Rule],
        union_membership: UnionMembership,
        execution_options: ExecutionOptions,
        local_store_options: LocalStoreOptions,
        executor: PyExecutor,
        include_trace_on_error: bool = True,
        visualize_to_dir: str | None = None,
        validate_reachability: bool = True,
        watch_filesystem: bool = True,
    ) -> None:
        """
        :param ignore_patterns: A list of gitignore-style file patterns for pants to ignore.
        :param use_gitignore: If set, pay attention to .gitignore files.
        :param build_root: The build root as a string.
        :param local_execution_root_dir: The directory to use for local execution sandboxes.
        :param named_caches_dir: The directory to use as the root for named mutable caches.
        :param ca_certs_path: Path to pem file for custom CA, if needed.
        :param rules: A set of Rules which is used to compute values in the graph.
        :param union_membership: All the registered and normalized union rules.
        :param execution_options: Execution options for (remote) processes.
        :param local_store_options: Options for the engine's LMDB store(s).
        :param include_trace_on_error: Include the trace through the graph upon encountering errors.
        :param validate_reachability: True to assert that all rules in an otherwise successfully
          constructed rule graph are reachable: if a graph cannot be successfully constructed, it
          is always a fatal error.
        :param watch_filesystem: False if filesystem watching should be disabled.
        """
        self.include_trace_on_error = include_trace_on_error
        self._visualize_to_dir = visualize_to_dir
        self._visualize_run_count = 0
        # Validate and register all provided and intrinsic tasks.
        rule_index = RuleIndex.create(rules)
        tasks = register_rules(rule_index, union_membership)

        # Create the native Scheduler and Session.
        types = PyTypes(
            paths=Paths,
            file_content=FileContent,
            file_entry=FileEntry,
            directory=Directory,
            digest_contents=DigestContents,
            digest_entries=DigestEntries,
            path_globs=PathGlobs,
            create_digest=CreateDigest,
            digest_subset=DigestSubset,
            download_file=DownloadFile,
            platform=Platform,
            process=Process,
            process_result=FallibleProcessResult,
            process_result_metadata=ProcessResultMetadata,
            coroutine=CoroutineType,
            session_values=SessionValues,
            run_id=RunId,
            interactive_process=InteractiveProcess,
            interactive_process_result=InteractiveProcessResult,
            engine_aware_parameter=EngineAwareParameter,
        )
        remoting_options = PyRemotingOptions(
            execution_enable=execution_options.remote_execution,
            store_address=execution_options.remote_store_address,
            execution_address=execution_options.remote_execution_address,
            execution_process_cache_namespace=execution_options.process_execution_cache_namespace,
            instance_name=execution_options.remote_instance_name,
            root_ca_certs_path=execution_options.remote_ca_certs_path,
            store_headers=execution_options.remote_store_headers,
            store_chunk_bytes=execution_options.remote_store_chunk_bytes,
            store_chunk_upload_timeout=execution_options.remote_store_chunk_upload_timeout_seconds,
            store_rpc_retries=execution_options.remote_store_rpc_retries,
            store_rpc_concurrency=execution_options.remote_store_rpc_concurrency,
            store_batch_api_size_limit=execution_options.remote_store_batch_api_size_limit,
            cache_warnings_behavior=execution_options.remote_cache_warnings.value,
            cache_eager_fetch=execution_options.remote_cache_eager_fetch,
            cache_rpc_concurrency=execution_options.remote_cache_rpc_concurrency,
            cache_read_timeout_millis=execution_options.remote_cache_read_timeout_millis,
            execution_extra_platform_properties=tuple(
                tuple(pair.split("=", 1))
                for pair in execution_options.remote_execution_extra_platform_properties
            ),
            execution_headers=execution_options.remote_execution_headers,
            execution_overall_deadline_secs=execution_options.remote_execution_overall_deadline_secs,
            execution_rpc_concurrency=execution_options.remote_execution_rpc_concurrency,
        )
        py_local_store_options = PyLocalStoreOptions(
            store_dir=local_store_options.store_dir,
            process_cache_max_size_bytes=local_store_options.processes_max_size_bytes,
            files_max_size_bytes=local_store_options.files_max_size_bytes,
            directories_max_size_bytes=local_store_options.directories_max_size_bytes,
            lease_time_millis=LOCAL_STORE_LEASE_TIME_SECS * 1000,
            shard_count=local_store_options.shard_count,
        )
        exec_stategy_opts = PyExecutionStrategyOptions(
            local_cache=execution_options.local_cache,
            remote_cache_read=execution_options.remote_cache_read,
            remote_cache_write=execution_options.remote_cache_write,
            local_cleanup=execution_options.process_cleanup,
            local_parallelism=execution_options.process_execution_local_parallelism,
            local_enable_nailgun=execution_options.process_execution_local_enable_nailgun,
            remote_parallelism=execution_options.process_execution_remote_parallelism,
        )

        self._py_scheduler = native_engine.scheduler_create(
            executor,
            tasks,
            types,
            build_root,
            local_execution_root_dir,
            named_caches_dir,
            ca_certs_path,
            ignore_patterns,
            use_gitignore,
            watch_filesystem,
            remoting_options,
            py_local_store_options,
>           exec_stategy_opts,
        )
E       ValueError: Encountered 3 rule graph errors:
E         No installed rules return the type UnionMembership, and it was not provided by potential callers of @rule(pants.bsp.rules:54:bsp_workspace_build_targets(WorkspaceBuildTargetsParams, UnionMembership) -> WorkspaceBuildTargetsResult).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.
E         No installed rules return the type UnionMembership, and it was not provided by potential callers of Query(UnionMembership for ()).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.
E         No installed rules return the type WorkspaceBuildTargetsParams, and it was not provided by potential callers of @rule(pants.bsp.rules:54:bsp_workspace_build_targets(WorkspaceBuildTargetsParams, UnionMembership) -> WorkspaceBuildTargetsResult).
E           If that type should be computed by a rule, ensure that that rule is installed.
E           If it should be provided by a caller, ensure that it is included in any relevant Query or Get.

src/python/pants/engine/internals/scheduler.py:225: ValueError
the
QueryRule
for
UnionMembership
should be brought in by the
*bsp_rules()
line
unless that test needs to supply a
UnionMembership
?
w
the issue is that
mk_scheduler
creates a
Scheduler
with no rules installed at all
to use it, you’d need to install a ton of infrastructure to get to the point where
engine_initializer
is: https://github.com/pantsbuild/pants/blob/b3b7e3ed1cd40df158fbbd86de64f4dac29481ef/src/python/pants/init/engine_initializer.py#L244-L246
so: use
RuleRunner
instead.
@fast-nail-55400: once you do that, you shouldn’t need a QueryRule for the UnionMembership, because the UnionMembership will already be a singleton in the graph.
(
RuleRunner
wraps
engine_initializer
)
f
isn’t
RuleRunner
only for tests?
w
yes… and this is a test afaict…?
in prod you will also be using a Scheduler that has been created via
engine_initializer
so using
RuleRunner
in a test aligns with that.
f
right but I need to pass a scheduler to
BSPConnection
w
rule_runner.scheduler
, iirc.
f
ah ok
w
sorry for the confusion
there is a lot of “default” infrastructure provided by `RuleRunner`/`engine_initializer` … while there are some tests that use
mk_scheduler
, they’re pretty limited, and have shrunk over time
f
I had used
mk_scheduler
only because it seemed like
SchedulerTestBase
was the way to go
w
yea. the inheritance-based infrastructure is effectively deprecated: 98% of stuff is using
RuleRunner
and pytest fixtures now
apparently
SchedulerTestBase
doesn’t mention that though… whoops!
(…and i missed that in #14329 … sorry about that.)
f
switching to
RuleRunner
fixed the rule graph issue. thanks!
👍 1