def visit_Call(self, call_node: ast.Call) -> None: get_args = self.maybe_extract_get_args(call_node) if get_args is not None: product_str, subject_str = GetConstraints.parse_input_and_output_types( get_args, source_file_name=self.source_file_name) get = GetConstraints(self.resolve_type(product_str), self.resolve_type(subject_str)) self.gets.append(get) # Ensure we descend into e.g. MultiGet(Get(...)...) calls. self.generic_visit(call_node)
def signature(cls): """Returns kwargs to construct a `TaskRule` that will construct the target Optionable. TODO: This indirection avoids a cycle between this module and the `rules` module. """ partial_construct_optionable = functools.partial( _construct_optionable, cls) # NB: We must populate several dunder methods on the partial function because partial # functions do not have these defined by default and the engine uses these values to # visualize functions in error messages and the rule graph. snake_scope = cls.options_scope.replace("-", "_") name = f"construct_scope_{snake_scope}" partial_construct_optionable.__name__ = name partial_construct_optionable.__module__ = cls.__module__ _, class_definition_lineno = inspect.getsourcelines(cls) partial_construct_optionable.__line_number__ = class_definition_lineno return dict( output_type=cls.optionable_cls, input_selectors=(), func=partial_construct_optionable, input_gets=(GetConstraints(output_type=ScopedOptions, input_type=Scope), ), canonical_name=name, )
def parse_get_types(get: str) -> Tuple[str, str]: get_args = ast.parse(get).body[0].value.args # type: ignore[attr-defined] return GetConstraints.parse_input_and_output_types( get_args, source_file_name="test.py")