将 LibCST 类型注释转换回类型?

问题描述 投票:0回答:1

创建将注释类型转换回类型的函数的开头后:

@typechecked
def extract_type_from_annotation(
    *,
    annotation: Union[
        Subscript, Index, Name, Annotation, Attribute, BinaryOperation
    ],
) -> str:
    """Extract the type information from an annotation.

    Args:
        annotation (Union[Subscript, Index, Name, Annotation]): The annotation
         to extract the type from.

    Returns:
        str: The extracted type information.
    """

    if isinstance(annotation, Subscript):
        # Handle the case where the annotation is a Subscript
        value = extract_type_from_annotation(annotation=annotation.value)
        slice_elements = [
            extract_type_from_annotation(annotation=slice_element.slice)
            for slice_element in annotation.slice
        ]
        return f"{value}[{', '.join(slice_elements)}]"
    if isinstance(annotation, Index):
        something = extract_type_from_annotation(annotation=annotation.value)
        return something
    if isinstance(annotation, Name):
        return str(annotation.value)
    if isinstance(annotation, Annotation):
        something = extract_type_from_annotation(
            annotation=annotation.annotation
        )
        return something
    if isinstance(annotation, Attribute):
        left = extract_type_from_annotation(annotation=annotation.value)
        right = extract_type_from_annotation(annotation=annotation.attr)
        something = f"{left}.{right}"
        return something
    if isinstance(annotation, BinaryOperation):
        left = extract_type_from_annotation(annotation=annotation.left)
        right = extract_type_from_annotation(annotation=annotation.right)
        something = f"{left}.{right}"

        return annotation
    return str(annotation)

我觉得我正在重新发明轮子。我希望这个功能已经内置到 LibCST 中,但是,我在找到它时遇到了一些困难。看完these

我在将其应用到

Annotation
对象时遇到了一些困难,例如:

code = Module([]).code_for_node(
                param.Annotation
            )

那样会抛出:

libcst._nodes.base.CSTCodegenError:如果指标上使用默认值,则必须指定具体的default_indicator。

问题

如何将 LibCST 中参数 Annotation 对象的类型重新转换为该类型的字符串?

annotations abstract-syntax-tree libcst
1个回答
0
投票

答案是将

Param
对象输入到 that 片段中,而不是
Annotation
对象。所以:

code = Module([]).code_for_node(
                param
            )

工作了(并产生了:

G: nx.DiGraph
)。

测试

这里是测试更新后的功能的测试:

"""Tests whether a dummy conversation can be outputted to a file."""
# pylint: disable=R0801
import unittest
from typing import Tuple

import libcst as cst
from libcst import Param, Parameters
from typeguard import typechecked

from jsonmodipy.get.argument_getting import extract_type_from_annotation
from tests.conftest import HardcodedTestdata


class Test_extract_type_from_annotation(unittest.TestCase):
    """Object used to test the get_type_from_param( method."""

    # Initialize test object
    @typechecked
    def __init__(  # type:ignore[no-untyped-def]
        self, *args, **kwargs
    ):
        super().__init__(*args, **kwargs)
        self.hardcoded_testdata: HardcodedTestdata = HardcodedTestdata()

    def test_returns_valid_type_for_binary_operator(self) -> None:
        """Verifies the extract_type_from_annotation( function returns a type
        with a binary operator succesfully."""
        function_header: str = """def plot_circular_graph(
    *,
    density: float,
    G: nx.DiGraph,
    recurrent_edge_density: int | float,
    test_scope: Long_scope_of_tests) -> None:
    \"\"\"Hello world.\"\"\""""
        # Parse the function header into libcst.
        source_tree = cst.parse_module(function_header)
        parameters: Parameters = source_tree.body[0].params
        kwonly_params: Tuple[Param, ...] = parameters.kwonly_params
        # Call the function to be tested.
        for param in kwonly_params:
            type_nanotation: str = extract_type_from_annotation(param=param)
            if param.name.value == "density":
                self.assertEqual(type_nanotation, "float")
            if param.name.value == "G":
                self.assertEqual(type_nanotation, "nx.DiGraph")
            if param.name.value == "recurrent_edge_density":
                self.assertEqual(type_nanotation, "int | float")
            if param.name.value == "test_scope":
                self.assertEqual(type_nanotation, "Long_scope_of_tests")

以及完整的功能:

@typechecked
def extract_type_from_annotation(
    *,
    param: Param,
) -> str:
    """Extract the type information from an annotation.

    Args:
        param Param: The parameter to extract the type from.

    Returns:
        str: The extracted type information.
    """
    parameter_text: str = Module([]).code_for_node(
        node=param,
    )

    # Remove any trailing spaces.
    parameter_text = parameter_text.strip()

    # Remove trailing commas if there are any.
    if parameter_text.endswith(","):
        parameter_text = parameter_text[:-1]

    # Split argument name and text into a list and get the type.
    the_type: str = parameter_text.split(":")[1].strip()

    return the_type

要获得问题的完整答案,如果没有

Annotation
对象,可以将填充名称与
Param
对象合并。这可以这样做:

param: Param = Param(name="filler", annotation=param.annotation)
© www.soinside.com 2019 - 2024. All rights reserved.