pydocstring 0.4.0

A zero-dependency Rust parser for Python docstrings (Google and NumPy styles) with a unified syntax tree and byte-precise source locations
Documentation
//! **Internal.** Demoted from the public API in 0.4.0 (#119): the unified view
//! (`parse::unified`) and the raw CST (`syntax`) are the public read lenses now.
//! These wrappers survive only as the reading layer `to_model` is written
//! against, and their surface is far wider than `to_model` uses — hence the
//! blanket `dead_code` allow. #107 restructures the section processors into one
//! shared block dispatcher, which is where this module dissolves; deleting the
//! unreachable half now would only conflict with that work.
#![allow(dead_code)]

//! NumPy-style section kind enumeration.

use core::fmt;

use crate::model::FreeSectionKind;
use crate::model::SectionKind;

/// NumPy-style section kinds.
///
/// Each variant represents a recognised section name (or group of aliases),
/// or [`Unknown`](Self::Unknown) for unrecognised names.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum NumPySectionKind {
    /// `Parameters` / `Params`
    Parameters,
    /// `Returns` / `Return`
    Returns,
    /// `Yields` / `Yield`
    Yields,
    /// `Receives` / `Receive`
    Receives,
    /// `Other Parameters` / `Other Params`
    OtherParameters,
    /// `Keyword Parameters` / `Keyword Arguments` / `Keyword Args`
    KeywordParameters,
    /// `Raises` / `Raise`
    Raises,
    /// `Warns` / `Warn`
    Warns,
    /// `Warnings` / `Warning`
    Warnings,
    /// `See Also`
    SeeAlso,
    /// `Notes` / `Note`
    Notes,
    /// `References`
    References,
    /// `Examples` / `Example`
    Examples,
    /// `Attributes`
    Attributes,
    /// `Methods`
    Methods,
    /// `Todo`
    Todo,
    /// `Attention`
    Attention,
    /// `Caution`
    Caution,
    /// `Danger`
    Danger,
    /// `Error`
    Error,
    /// `Hint`
    Hint,
    /// `Important`
    Important,
    /// `Tip`
    Tip,
    /// Unrecognised section name.
    Unknown,
}

impl NumPySectionKind {
    /// The [`EntryRole`](crate::parse::EntryRole) of this section's body
    /// entries.
    ///
    /// Shared by the visitor's `ENTRY` routing and the typed section
    /// accessors' role guards.
    pub(crate) fn entry_role(self) -> crate::parse::EntryRole {
        use crate::parse::EntryRole;
        match self {
            Self::Parameters | Self::OtherParameters | Self::Receives | Self::KeywordParameters => EntryRole::Parameter,
            Self::Returns => EntryRole::Return,
            Self::Yields => EntryRole::Yield,
            Self::Raises => EntryRole::Exception,
            Self::Warns => EntryRole::Warning,
            Self::SeeAlso => EntryRole::SeeAlsoItem,
            Self::Attributes => EntryRole::Attribute,
            Self::Methods => EntryRole::Method,
            Self::References => EntryRole::Citation,
            // Notes, Examples, Todo, Warnings, admonitions, Unknown, and any
            // future kinds: free-text body, no entries.
            _ => EntryRole::FreeText,
        }
    }

    /// All known section kinds.
    pub const ALL: &[NumPySectionKind] = &[
        Self::Parameters,
        Self::Returns,
        Self::Yields,
        Self::Receives,
        Self::OtherParameters,
        Self::KeywordParameters,
        Self::Raises,
        Self::Warns,
        Self::Warnings,
        Self::SeeAlso,
        Self::Notes,
        Self::References,
        Self::Examples,
        Self::Attributes,
        Self::Methods,
        Self::Todo,
        Self::Attention,
        Self::Caution,
        Self::Danger,
        Self::Error,
        Self::Hint,
        Self::Important,
        Self::Tip,
    ];

    /// Convert a **lowercased** section name to a [`NumPySectionKind`].
    #[rustfmt::skip]
    pub fn from_name(name: &str) -> Self {
        match name {
            "parameters" | "parameter" | "params" | "param" => Self::Parameters,
            "arguments" | "argument" | "args" | "arg" => Self::Parameters,
            "returns" | "return" => Self::Returns,
            "yields" | "yield" => Self::Yields,
            "receives" | "receive" => Self::Receives,
            "other parameters" | "other parameter" | "other params" | "other param" => Self::OtherParameters,
            "other arguments" | "other argument" | "other args" | "other arg" => Self::OtherParameters,
            "keyword parameters" | "keyword parameter" | "keyword params" | "keyword param" => Self::KeywordParameters,
            "keyword arguments" | "keyword argument" | "keyword args" | "keyword arg" => Self::KeywordParameters,
            "raises" | "raise" => Self::Raises,
            "warns" | "warn" => Self::Warns,
            "warnings" | "warning" => Self::Warnings,
            "see also" => Self::SeeAlso,
            "notes" | "note" => Self::Notes,
            "references" | "reference" => Self::References,
            "examples" | "example" => Self::Examples,
            "attributes" | "attribute" => Self::Attributes,
            "methods" | "method" => Self::Methods,
            "todo" => Self::Todo,
            "attention" => Self::Attention,
            "caution" => Self::Caution,
            "danger" => Self::Danger,
            "error" => Self::Error,
            "hint" => Self::Hint,
            "important" => Self::Important,
            "tip" => Self::Tip,
            _ => Self::Unknown,
        }
    }

    /// Check if a lowercased name is a known (non-[`Unknown`](Self::Unknown)) section name.
    pub fn is_known(name: &str) -> bool {
        !matches!(Self::from_name(name), Self::Unknown)
    }

    /// Map to the style-independent [`SectionKind`] of the model layer.
    ///
    /// `header_name` is the section header text as written, used for
    /// [`FreeSectionKind::Unknown`].
    #[rustfmt::skip]
    pub fn to_section_kind(self, header_name: &str) -> SectionKind {
        match self {
            Self::Parameters => SectionKind::Parameters,
            Self::KeywordParameters => SectionKind::KeywordParameters,
            Self::OtherParameters => SectionKind::OtherParameters,
            Self::Receives => SectionKind::Receives,
            Self::Returns => SectionKind::Returns,
            Self::Yields => SectionKind::Yields,
            Self::Raises => SectionKind::Raises,
            Self::Warns => SectionKind::Warns,
            Self::Attributes => SectionKind::Attributes,
            Self::Methods => SectionKind::Methods,
            Self::SeeAlso => SectionKind::SeeAlso,
            Self::References => SectionKind::References,
            Self::Notes => SectionKind::FreeText(FreeSectionKind::Notes),
            Self::Examples => SectionKind::FreeText(FreeSectionKind::Examples),
            Self::Warnings => SectionKind::FreeText(FreeSectionKind::Warnings),
            Self::Todo => SectionKind::FreeText(FreeSectionKind::Todo),
            Self::Attention => SectionKind::FreeText(FreeSectionKind::Attention),
            Self::Caution => SectionKind::FreeText(FreeSectionKind::Caution),
            Self::Danger => SectionKind::FreeText(FreeSectionKind::Danger),
            Self::Error => SectionKind::FreeText(FreeSectionKind::Error),
            Self::Hint => SectionKind::FreeText(FreeSectionKind::Hint),
            Self::Important => SectionKind::FreeText(FreeSectionKind::Important),
            Self::Tip => SectionKind::FreeText(FreeSectionKind::Tip),
            Self::Unknown => SectionKind::FreeText(FreeSectionKind::Unknown(header_name.to_owned())),
        }
    }

    /// Whether this section kind has structured entries (vs free text).
    pub fn is_structured(&self) -> bool {
        matches!(
            self,
            Self::Parameters
                | Self::Returns
                | Self::Yields
                | Self::Receives
                | Self::OtherParameters
                | Self::KeywordParameters
                | Self::Raises
                | Self::Warns
                | Self::SeeAlso
                | Self::References
                | Self::Attributes
                | Self::Methods
        )
    }

    /// Whether this section kind has free-text body.
    pub fn is_freetext(&self) -> bool {
        matches!(
            self,
            Self::Notes
                | Self::Examples
                | Self::Warnings
                | Self::Todo
                | Self::Attention
                | Self::Caution
                | Self::Danger
                | Self::Error
                | Self::Hint
                | Self::Important
                | Self::Tip
                | Self::Unknown
        )
    }
}

impl fmt::Display for NumPySectionKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            Self::Parameters => "Parameters",
            Self::Returns => "Returns",
            Self::Yields => "Yields",
            Self::Receives => "Receives",
            Self::OtherParameters => "Other Parameters",
            Self::KeywordParameters => "Keyword Parameters",
            Self::Raises => "Raises",
            Self::Warns => "Warns",
            Self::Warnings => "Warnings",
            Self::SeeAlso => "See Also",
            Self::Notes => "Notes",
            Self::References => "References",
            Self::Examples => "Examples",
            Self::Attributes => "Attributes",
            Self::Methods => "Methods",
            Self::Todo => "Todo",
            Self::Attention => "Attention",
            Self::Caution => "Caution",
            Self::Danger => "Danger",
            Self::Error => "Error",
            Self::Hint => "Hint",
            Self::Important => "Important",
            Self::Tip => "Tip",
            Self::Unknown => "Unknown",
        };
        write!(f, "{}", s)
    }
}