Beispiel #1
0
    def read_parameters_section(self, lines: List[str], start_index: int) -> Tuple[Optional[Section], int]:
        """
        Parse a "parameters" section.

        Arguments:
            lines: The parameters block lines.
            start_index: The line number to start at.

        Returns:
            A tuple containing a `Section` (or `None`) and the index at which to continue parsing.
        """
        parameters = []
        type_: Any
        block, i = self.read_block_items(lines, start_index)

        for param_line in block:
            try:
                name_with_type, description = param_line.split(":", 1)
            except ValueError:
                self.error(f"Failed to get 'name: description' pair from '{param_line}'")
                continue

            description = description.lstrip()

            if " " in name_with_type:
                name, type_ = name_with_type.split(" ", 1)
                type_ = type_.strip("()")
                if type_.endswith(", optional"):
                    type_ = type_[:-10]
            else:
                name = name_with_type
                type_ = empty

            default = empty
            annotation = type_
            kind = None

            try:
                signature_param = self.context["signature"].parameters[name.lstrip("*")]  # type: ignore
            except (AttributeError, KeyError):
                self.error(f"No type annotation for parameter '{name}'")
            else:
                if signature_param.annotation is not empty:
                    annotation = signature_param.annotation
                if signature_param.default is not empty:
                    default = signature_param.default
                kind = signature_param.kind

            parameters.append(
                Parameter(name=name, annotation=annotation, description=description, default=default, kind=kind)
            )

        if parameters:
            return Section(Section.Type.PARAMETERS, parameters), i

        self.error(f"Empty parameters section at line {start_index}")
        return None, i
def test_parse__param_field_multi_line__param_section(docstring):
    """Parse a simple docstring."""
    sections, errors = parse_detailed(docstring)
    assert len(sections) == 2
    assert sections[1].type == Section.Type.PARAMETERS
    assert_parameter_equal(
        sections[1].value[0],
        Parameter(SOME_NAME,
                  annotation=empty,
                  description=f"{SOME_TEXT} {SOME_EXTRA_TEXT}",
                  kind=empty),
    )
def test_member_function___expected_param():
    class_ = get_rst_object_documentation("class_docstrings:ClassWithFunction")
    init = class_.methods[0]
    sections = init.docstring_sections
    assert len(sections) == 3
    param_section = sections[1]
    assert param_section.type == Section.Type.PARAMETERS
    assert_parameter_equal(
        param_section.value[0],
        Parameter("value",
                  str,
                  "Value to store",
                  kind=inspect.Parameter.POSITIONAL_OR_KEYWORD))
    assert_parameter_equal(
        param_section.value[1],
        Parameter("other",
                  "int",
                  "Other value with default",
                  kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
                  default=1),
    )
Beispiel #4
0
    def read_parameters_section(
        self,
        docstring: str,
        docstring_obj: Docstring,
    ) -> Optional[Section]:
        """
        Parse a "parameters" section.

        Arguments:
            lines: The parameters block lines.
            start_index: The line number to start at.

        Returns:
            A tuple containing a `Section` (or `None`) and the index at which to continue parsing.
        """
        parameters = []

        docstring_params = [
            p for p in docstring_obj.params if p.args[0] == "param"
        ]

        for param in docstring_params:
            name = param.arg_name
            kind = None
            type_name = param.type_name
            default = param.default or empty
            try:
                signature_param = self.context["signature"].parameters[
                    name.lstrip("*")]  # type: ignore
            except (AttributeError, KeyError):
                self.error(f"No type annotation for parameter '{name}'")
            else:
                if signature_param.annotation is not empty:
                    type_name = signature_param.annotation
                if signature_param.default is not empty:
                    default = signature_param.default
                kind = signature_param.kind
            parameters.append(
                Parameter(
                    name=param.arg_name,
                    annotation=type_name,
                    description=param.description,
                    default=default,
                    kind=kind,
                ))

        if parameters:
            return Section(Section.Type.PARAMETERS, parameters)
        if re.search("Parameters\n", docstring):
            self.error("Empty parameter section")
        return None
def test_parse__all_param_names__param_section(param_directive_name):
    sections, errors = parse_detailed(f"""
        Docstring with one line param.

        :{param_directive_name} {SOME_NAME}: {SOME_TEXT}
        """)
    assert len(sections) == 2
    assert sections[1].type == Section.Type.PARAMETERS
    assert_parameter_equal(
        sections[1].value[0],
        Parameter(SOME_NAME,
                  annotation=empty,
                  description=SOME_TEXT,
                  kind=empty))
def test_parse__param_field__param_section():
    """Parse a simple docstring."""
    sections, errors = parse_detailed(f"""
        Docstring with one line param.

        :param {SOME_NAME}: {SOME_TEXT}
        """)
    assert len(sections) == 2
    assert sections[1].type == Section.Type.PARAMETERS
    assert_parameter_equal(
        sections[1].value[0],
        Parameter(SOME_NAME,
                  annotation=empty,
                  description=SOME_TEXT,
                  kind=empty))
def test_parse__param_field_no_matching_param__result_from_docstring():
    """Parse a simple docstring."""
    def f(foo: str):
        """
        Docstring with line continuation.

        :param other: descriptive test text
        """

    sections, errors = parse(f)
    assert len(sections) == 2
    assert sections[1].type == Section.Type.PARAMETERS
    assert_parameter_equal(
        sections[1].value[0],
        Parameter("other", annotation=empty, description=SOME_TEXT,
                  kind=empty),
    )
    def _read_parameter(self, lines: List[str], start_index: int) -> int:
        """
        Parse a parameter value.

        Arguments:
            lines: The docstring lines.
            start_index: The line number to start at.

        Returns:
            Index at which to continue parsing.
        """
        parsed_directive = self._parse_directive(lines, start_index)
        if parsed_directive.invalid:
            return parsed_directive.next_index

        directive_type = None
        if len(parsed_directive.directive_parts) == 2:
            # no type info
            name = parsed_directive.directive_parts[1]
        elif len(parsed_directive.directive_parts) == 3:
            directive_type = parsed_directive.directive_parts[1]
            name = parsed_directive.directive_parts[2]
        else:
            self.error(
                f"Failed to parse field directive from '{parsed_directive.line}'"
            )
            return parsed_directive.next_index

        if name in self._parsed_values.parameters:
            self.errors.append(f"Duplicate parameter entry for '{name}'")
            return parsed_directive.next_index

        annotation = self._determine_param_annotation(name, directive_type)
        default, kind = self._determine_param_details(name)

        self._parsed_values.parameters[name] = Parameter(
            name=name,
            annotation=annotation,
            description=parsed_directive.value,
            default=default,
            kind=kind,
        )

        return parsed_directive.next_index
def test_parse__param_field_annotate_type__param_section_with_type():
    """Parse a simple docstring."""
    def f(foo: str):
        """
        Docstring with line continuation.

        :param foo: descriptive test text
        """

    sections, errors = parse(f)
    assert len(sections) == 2
    assert sections[1].type == Section.Type.PARAMETERS
    assert_parameter_equal(
        sections[1].value[0],
        Parameter(SOME_NAME,
                  annotation=str,
                  description=SOME_TEXT,
                  kind=inspect.Parameter.POSITIONAL_OR_KEYWORD),
    )
def test_parse__param_field_with_default__result_from_docstring():
    """Parse a simple docstring."""
    def f(foo=""):
        """
        Docstring with line continuation.

        :param foo: descriptive test text
        """

    sections, errors = parse(f)
    assert len(sections) == 2
    assert sections[1].type == Section.Type.PARAMETERS
    assert_parameter_equal(
        sections[1].value[0],
        Parameter("foo",
                  annotation=empty,
                  description=SOME_TEXT,
                  default="",
                  kind=inspect.Parameter.POSITIONAL_OR_KEYWORD),
    )
def test_parse__param_field_type_multiple__param_section_with_union():
    """Parse a simple docstring."""
    def f(foo):
        """
        Docstring with line continuation.

        :param foo: descriptive test text
        :type foo: str or int or float
        """

    sections, errors = parse(f)
    assert len(sections) == 2
    assert sections[1].type == Section.Type.PARAMETERS
    assert_parameter_equal(
        sections[1].value[0],
        Parameter(
            SOME_NAME,
            annotation="Union[str,int,float]",
            description=SOME_TEXT,
            kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
        ),
    )