From b0d6fd7343e503f1ec2917db339fe88639d84911 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 23 Jan 2024 23:26:02 -0500 Subject: [PATCH] Generate custom JSON schema for dynamic setting (#9632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary If you paste in the TOML for our default configuration (from the docs), it's rejected by our JSON Schema: ![Screenshot 2024-01-23 at 10 08 09 PM](https://github.com/astral-sh/ruff/assets/1309177/7b4ea6e8-07db-4590-bd1e-73a01a35d747) It seems like the issue is with: ```toml # Set the line length limit used when formatting code snippets in # docstrings. # # This only has an effect when the `docstring-code-format` setting is # enabled. docstring-code-line-length = "dynamic" ``` Specifically, since that value uses a custom Serde implementation, I guess Schemars bails out? This PR adds a custom representation to allow `"dynamic"` (but no other strings): ![Screenshot 2024-01-23 at 10 27 21 PM](https://github.com/astral-sh/ruff/assets/1309177/ab7809d4-b077-44e9-8f98-ed893aaefe5d) This seems like it should work but I don't have a great way to test it. Closes https://github.com/astral-sh/ruff/issues/9630. --- crates/ruff_python_formatter/src/options.rs | 31 +++++++++++++++++++-- ruff.schema.json | 18 ++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index 122a9909e9..e4022a5889 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -1,10 +1,11 @@ +use std::fmt; +use std::path::Path; +use std::str::FromStr; + use ruff_formatter::printer::{LineEnding, PrinterOptions, SourceMapGeneration}; use ruff_formatter::{FormatOptions, IndentStyle, IndentWidth, LineWidth}; use ruff_macros::CacheKey; use ruff_python_ast::PySourceType; -use std::fmt; -use std::path::Path; -use std::str::FromStr; /// Resolved options for formatting one individual file. The difference to `FormatterSettings` /// is that `FormatterSettings` stores the settings for multiple files (the entire project, a subdirectory, ..) @@ -367,15 +368,39 @@ impl fmt::Display for DocstringCode { #[cfg_attr(feature = "serde", serde(untagged))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum DocstringCodeLineWidth { + /// Wrap docstring code examples at a fixed line width. Fixed(LineWidth), + + /// Respect the line length limit setting for the surrounding Python code. #[default] #[cfg_attr( feature = "serde", serde(deserialize_with = "deserialize_docstring_code_line_width_dynamic") )] + #[cfg_attr(feature = "schemars", schemars(with = "DynamicSchema"))] Dynamic, } +/// A dummy type that is used to generate a schema for `DocstringCodeLineWidth::Dynamic`. +#[cfg(feature = "schemars")] +struct DynamicSchema; + +#[cfg(feature = "schemars")] +impl schemars::JsonSchema for DynamicSchema { + fn schema_name() -> String { + "Dynamic".to_string() + } + + fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { + schemars::schema::SchemaObject { + instance_type: Some(schemars::schema::InstanceType::String.into()), + const_value: Some("dynamic".to_string().into()), + ..Default::default() + } + .into() + } +} + impl fmt::Debug for DocstringCodeLineWidth { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/ruff.schema.json b/ruff.schema.json index 65a83ce31c..54e7656c6d 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -750,13 +750,27 @@ "DocstringCodeLineWidth": { "anyOf": [ { - "$ref": "#/definitions/LineWidth" + "description": "Wrap docstring code examples at a fixed line width.", + "allOf": [ + { + "$ref": "#/definitions/LineWidth" + } + ] }, { - "type": "null" + "description": "Respect the line length limit setting for the surrounding Python code.", + "allOf": [ + { + "$ref": "#/definitions/Dynamic" + } + ] } ] }, + "Dynamic": { + "type": "string", + "const": "dynamic" + }, "Flake8AnnotationsOptions": { "type": "object", "properties": {