Skip to content

Conversation

@ShaharNaveh
Copy link
Contributor

Fixes #20823

Summary

Implemented code from original issue

Test Plan

Added test

@github-actions
Copy link
Contributor

github-actions bot commented Oct 25, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@chirizxc
Copy link
Contributor

My implementation example doesn't seem quite right.

I don't think we should prohibit people from setting line-length to more than 320, maybe we should just give a warning? (but it will change the current behavior)

@ShaharNaveh
Copy link
Contributor Author

My implementation example doesn't seem quite right.

I don't think we should prohibit people from setting line-length to more than 320, maybe we should just give a warning? (but it will change the current behavior)

IMO, there's no need for having artificial constraints about the max size of the line-length, or a need to set a warning, the way that I see it, if a user explicitly set line-length to 10000 he knows what he's doing (I hope so). I am not saying that there's a need for increasing the possible length (by utilizing NonZerou32).


One possible solution would be to remove

/// Maximum allowed value for a valid [`LineLength`]
pub const MAX: u16 = 320;

And relying on the constrains of NonZerou16 at:

impl TryFrom<u16> for LineLength {
type Error = LineLengthFromIntError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match NonZeroU16::try_from(value) {
Ok(value) if value.get() <= Self::MAX => Ok(LineLength(value)),
Ok(_) | Err(_) => Err(LineLengthFromIntError(value)),
}
}
}

@chirizxc
Copy link
Contributor

chirizxc commented Oct 25, 2025

It seems that the root of the problem lies in crate toml.

@chirizxc
Copy link
Contributor

although it seems that the TOML specification mentions this

Non-negative integer values may also be expressed in hexadecimal, octal, or binary. In these formats, leading + is not allowed and leading zeros are allowed (after the prefix). Hex values are case-insensitive. Underscores are allowed between digits (but not between the prefix and the value).

# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef

# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions

# binary with prefix `0b`
bin1 = 0b11010110

Arbitrary 64-bit signed integers (from −2^63 to 2^63−1) should be accepted and handled losslessly. If an integer cannot be represented losslessly, an error must be thrown.

@ShaharNaveh
Copy link
Contributor Author

If an integer cannot be represented losslessly, an error must be thrown.

So if I understand you correctly it will be something like:

let raw = match i64::deserialize(deserializer) {
  Ok(v) => v,
  Err(_) => {
    let s: &str = Deserializer::deserialize(deserializer)?;
    i64::from_str(s).map_err(ParseLineWidthError::ParseError)?
  }
}

let value = u16::try_from(raw).map_err(???)

The main issue with this approach is that

/// Error type returned when converting a u16 to a [`LineLength`] fails
#[derive(Clone, Copy, Debug)]
pub struct LineLengthFromIntError(pub u16);

can only store u16 and in the best case with this approach we'll have i64. It doesn't make much sense to change the type to i64. what does deserlizing to i64 first gives us? why can't we just do what you suggested initially?

Comment on lines 55 to 62
let value = NonZeroU16::try_from(value).map_err(|_| {
serde::de::Error::custom(format!(
"line-length must be between 1 and {} (got {value})",
Self::MAX,
))
})?;

Self::try_from(value.get()).map_err(serde::de::Error::custom)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Maybe something like this:

Suggested change
let value = NonZeroU16::try_from(value).map_err(|_| {
serde::de::Error::custom(format!(
"line-length must be between 1 and {} (got {value})",
Self::MAX,
))
})?;
Self::try_from(value.get()).map_err(serde::de::Error::custom)
let value = Self::try_from(value).map_err(|_| {
serde::de::Error::custom(format!(
"line-length must be between 1 and {} (got {value})",
Self::MAX,
))
})

ShaharNaveh and others added 2 commits October 25, 2025 20:38
Co-authored-by: Micha Reiser <micha@reiser.io>
Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@MichaReiser MichaReiser enabled auto-merge (squash) October 27, 2025 07:37
@MichaReiser MichaReiser merged commit fa12fd0 into astral-sh:main Oct 27, 2025
36 checks passed
dcreager added a commit that referenced this pull request Oct 27, 2025
* origin/main:
  Respect `--output-format` with `--watch` (#21097)
  [`pyflakes`] Revert to stable behavior if imports for module lie in alternate branches for `F401` (#20878)
  Fix finding keyword range for clause header after statement ending with semicolon (#21067)
  [ty] Fix bug where ty would think all types had an `__mro__` attribute (#20995)
  Restore `indent.py` (#21094)
  [`flake8-django`] Apply `DJ001` to annotated fields (#20907)
  Clearer error message when `line-length` goes beyond threshold (#21072)
  Update upload and download artifacts github actions (#21083)
  Update dependency mdformat-mkdocs to v4.4.2 (#21088)
  Update cargo-bins/cargo-binstall action to v1.15.9 (#21086)
  Update Rust crate clap to v4.5.50 (#21090)
  Update Rust crate get-size2 to v0.7.1 (#21091)
  Update Rust crate bstr to v1.12.1 (#21089)
  Add missing docstring sections to the numpy list (#20931)
  [`pydoclint`] Fix false positive on explicit exception re-raising (`DOC501`, `DOC502`) (#21011)
  [ty] Use constructor parameter types as type context (#21054)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unclear error if line-length goes beyond u16 boundaries

3 participants