Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.3] - 2026-03-19

### Added

- Section name matching now accepts additional singular and alias forms for both
Google and NumPy styles:
- `"arg"`, `"param"`, `"keyword arg"`, `"keyword param"`, `"other arg"`,
`"other param"`, `"method"`, `"reference"` (Google)
- `"arguments"`, `"argument"`, `"args"`, `"arg"`, `"other arguments"`,
`"other argument"`, `"other args"`, `"other arg"`, `"attribute"`,
`"method"`, `"reference"` (NumPy)
- Common typos tolerated: `"argment"`, `"paramter"` (Google)

### Fixed

- Google parser: arg entries with no description (e.g. `b :`) inside a section
body were incorrectly classified as new section headers. Fixed by comparing
the indentation of each line against the current section header's indentation
and skipping header detection for more-indented lines.

### Changed

- Refactored Google entry header parsing to use a left-to-right confirmation
algorithm. Handles missing close brackets, missing colons, and text after
brackets without a colon more robustly. `close_bracket` in `TypeInfo` is now
`Option<TextRange>` to represent the missing-bracket case.
- Added `rustfmt.toml` (`max_width = 120`) and reformatted all source files.

## [0.1.2] - 2026-03-16

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pydocstring"
version = "0.1.2"
version = "0.1.3"
edition = "2024"
authors = ["Ryuma Asai"]
description = "A zero-dependency Rust parser for Python docstrings (Google and NumPy styles) with a unified syntax tree and byte-precise source locations"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Python bindings are also available as [`pydocstring-rs`](https://pypi.org/projec

```toml
[dependencies]
pydocstring = "0.1.2"
pydocstring = "0.1.3"
```

## Usage
Expand Down
4 changes: 2 additions & 2 deletions bindings/python/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pydocstring-python"
version = "0.1.2"
version = "0.1.3"
edition = "2024"
authors = ["Ryuma Asai"]
description = "Python bindings for pydocstring — a fast docstring parser for Google and NumPy styles"
Expand All @@ -12,5 +12,5 @@ name = "pydocstring"
crate-type = ["cdylib"]

[dependencies]
pydocstring_core = { package = "pydocstring", version = "0.1.2", path = "../.." }
pydocstring_core = { package = "pydocstring", version = "0.1.3", path = "../.." }
pyo3 = { version = "0.24", features = ["extension-module"] }
2 changes: 1 addition & 1 deletion bindings/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "maturin"

[project]
name = "pydocstring-rs"
version = "0.1.2"
version = "0.1.3"
description = "Python bindings for pydocstring — a zero-dependency Rust parser for Python docstrings (Google and NumPy styles) with a unified syntax tree and byte-precise source locations"
license = {text = "MIT"}
authors = [{name = "Ryuma Asai"}]
Expand Down
1 change: 1 addition & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
max_width = 120
19 changes: 3 additions & 16 deletions src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,7 @@ impl<'a> LineCursor<'a> {
/// Equivalent to
/// `make_line_range(line, current_indent(), current_trimmed().len())`.
pub fn current_trimmed_range(&self) -> TextRange {
self.make_line_range(
self.line,
self.current_indent(),
self.current_trimmed().len(),
)
self.make_line_range(self.line, self.current_indent(), self.current_trimmed().len())
}

// ── Arbitrary-line helpers ──────────────────────────────────────
Expand All @@ -140,13 +136,7 @@ impl<'a> LineCursor<'a> {
// ── Span construction ──────────────────────────────────────────

/// Build a [`TextRange`] from (line, col) pairs.
pub fn make_range(
&self,
start_line: usize,
start_col: usize,
end_line: usize,
end_col: usize,
) -> TextRange {
pub fn make_range(&self, start_line: usize, start_col: usize, end_line: usize, end_col: usize) -> TextRange {
TextRange::new(
TextSize::new((self.offsets[start_line] + start_col) as u32),
TextSize::new((self.offsets[end_line] + end_col) as u32),
Expand Down Expand Up @@ -186,10 +176,7 @@ impl<'a> LineCursor<'a> {

/// Convert a byte offset to `(line, col)`.
pub fn offset_to_line_col(&self, offset: usize) -> (usize, usize) {
let line = self
.offsets
.partition_point(|&o| o <= offset)
.saturating_sub(1);
let line = self.offsets.partition_point(|&o| o <= offset).saturating_sub(1);
let col = offset - self.offsets[line];
(line, col)
}
Expand Down
3 changes: 1 addition & 2 deletions src/emit/google.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! Emit a [`Docstring`] as a Google-style docstring.

use crate::model::{
Attribute, Docstring, ExceptionEntry, FreeSectionKind, Method, Parameter, Reference, Return,
Section, SeeAlsoEntry,
Attribute, Docstring, ExceptionEntry, FreeSectionKind, Method, Parameter, Reference, Return, Section, SeeAlsoEntry,
};

/// Emit a [`Docstring`] as a Google-style docstring string.
Expand Down
4 changes: 2 additions & 2 deletions src/emit/numpy.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Emit a [`Docstring`] as a NumPy-style docstring.

use crate::model::{
Attribute, Deprecation, Docstring, ExceptionEntry, FreeSectionKind, Method, Parameter,
Reference, Return, Section, SeeAlsoEntry,
Attribute, Deprecation, Docstring, ExceptionEntry, FreeSectionKind, Method, Parameter, Reference, Return, Section,
SeeAlsoEntry,
};

/// Emit a [`Docstring`] as a NumPy-style docstring string.
Expand Down
6 changes: 1 addition & 5 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,7 @@ fn has_numpy_sections(input: &str) -> bool {
for i in 0..lines.len().saturating_sub(1) {
let current = lines[i].trim();
let next = lines[i + 1].trim();
if !current.is_empty()
&& !next.is_empty()
&& next.len() >= 3
&& next.chars().all(|c| c == '-')
{
if !current.is_empty() && !next.is_empty() && next.len() >= 3 && next.chars().all(|c| c == '-') {
return true;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/parse/google.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub mod to_model;

pub use kind::GoogleSectionKind;
pub use nodes::{
GoogleArg, GoogleAttribute, GoogleDocstring, GoogleException, GoogleMethod, GoogleReturns,
GoogleSection, GoogleSectionHeader, GoogleSeeAlsoItem, GoogleWarning,
GoogleArg, GoogleAttribute, GoogleDocstring, GoogleException, GoogleMethod, GoogleReturns, GoogleSection,
GoogleSectionHeader, GoogleSeeAlsoItem, GoogleWarning,
};
pub use parser::parse_google;
13 changes: 8 additions & 5 deletions src/parse/google/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,24 @@ impl GoogleSectionKind {
#[rustfmt::skip]
pub fn from_name(name: &str) -> Self {
match name {
"args" | "arguments" | "params" | "parameters" => Self::Args,
"keyword args" | "keyword arguments" | "keyword params" | "keyword parameters" => Self::KeywordArgs,
"other args" | "other arguments" | "other params" | "other parameters" => Self::OtherParameters,
"args" | "arg" | "arguments" | "argment" => Self::Args,
"params" | "param" | "parameters" | "paramter" => Self::Args,
"keyword args" | "keyword arg" | "keyword arguments" | "keyword argument" => Self::KeywordArgs,
"keyword params" | "keyword param" | "keyword parameters" | "keyword paramter" => Self::KeywordArgs,
"other args" | "other arg" | "other arguments" | "other argment" => Self::OtherParameters,
"other params" | "other param" | "other parameters" | "other paramter" => Self::OtherParameters,
"receives" | "receive" => Self::Receives,
"returns" | "return" => Self::Returns,
"yields" | "yield" => Self::Yields,
"raises" | "raise" => Self::Raises,
"warns" | "warn" => Self::Warns,
"see also" => Self::SeeAlso,
"attributes" | "attribute" => Self::Attributes,
"methods" => Self::Methods,
"methods" | "method" => Self::Methods,
"notes" | "note" => Self::Notes,
"examples" | "example" => Self::Examples,
"todo" => Self::Todo,
"references" => Self::References,
"references" | "reference" => Self::References,
"warnings" | "warning" => Self::Warnings,
"attention" => Self::Attention,
"caution" => Self::Caution,
Expand Down
16 changes: 4 additions & 12 deletions src/parse/google/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ impl<'a> GoogleDocstring<'a> {

/// Iterate over all section nodes.
pub fn sections(&self) -> impl Iterator<Item = GoogleSection<'a>> {
self.0
.nodes(SyntaxKind::GOOGLE_SECTION)
.filter_map(GoogleSection::cast)
self.0.nodes(SyntaxKind::GOOGLE_SECTION).filter_map(GoogleSection::cast)
}

/// Iterate over stray line tokens.
Expand Down Expand Up @@ -86,9 +84,7 @@ impl<'a> GoogleSection<'a> {

/// Iterate over arg entry nodes in this section.
pub fn args(&self) -> impl Iterator<Item = GoogleArg<'a>> {
self.0
.nodes(SyntaxKind::GOOGLE_ARG)
.filter_map(GoogleArg::cast)
self.0.nodes(SyntaxKind::GOOGLE_ARG).filter_map(GoogleArg::cast)
}

/// Returns entry node in this section, if present.
Expand All @@ -107,9 +103,7 @@ impl<'a> GoogleSection<'a> {

/// Iterate over warning entry nodes.
pub fn warnings(&self) -> impl Iterator<Item = GoogleWarning<'a>> {
self.0
.nodes(SyntaxKind::GOOGLE_WARNING)
.filter_map(GoogleWarning::cast)
self.0.nodes(SyntaxKind::GOOGLE_WARNING).filter_map(GoogleWarning::cast)
}

/// Iterate over see-also item nodes.
Expand All @@ -128,9 +122,7 @@ impl<'a> GoogleSection<'a> {

/// Iterate over method entry nodes.
pub fn methods(&self) -> impl Iterator<Item = GoogleMethod<'a>> {
self.0
.nodes(SyntaxKind::GOOGLE_METHOD)
.filter_map(GoogleMethod::cast)
self.0.nodes(SyntaxKind::GOOGLE_METHOD).filter_map(GoogleMethod::cast)
}

/// Free-text body content, if this is a free-text section.
Expand Down
Loading
Loading