mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-31 03:55:09 +00:00 
			
		
		
		
	 015222900f
			
		
	
	
		015222900f
		
			
		
	
	
	
		
			
	
		
	
	
		
			Some checks are pending
		
		
	
	CI / Determine changes (push) Waiting to run
				
			CI / cargo fmt (push) Waiting to run
				
			CI / cargo clippy (push) Blocked by required conditions
				
			CI / cargo test (linux) (push) Blocked by required conditions
				
			CI / cargo test (linux, release) (push) Blocked by required conditions
				
			CI / cargo test (windows) (push) Blocked by required conditions
				
			CI / cargo test (wasm) (push) Blocked by required conditions
				
			CI / cargo build (release) (push) Waiting to run
				
			CI / cargo build (msrv) (push) Blocked by required conditions
				
			CI / cargo fuzz build (push) Blocked by required conditions
				
			CI / fuzz parser (push) Blocked by required conditions
				
			CI / test scripts (push) Blocked by required conditions
				
			CI / ecosystem (push) Blocked by required conditions
				
			CI / Fuzz for new ty panics (push) Blocked by required conditions
				
			CI / cargo shear (push) Blocked by required conditions
				
			CI / python package (push) Waiting to run
				
			CI / pre-commit (push) Waiting to run
				
			CI / mkdocs (push) Waiting to run
				
			CI / formatter instabilities and black similarity (push) Blocked by required conditions
				
			CI / test ruff-lsp (push) Blocked by required conditions
				
			CI / check playground (push) Blocked by required conditions
				
			CI / benchmarks (push) Blocked by required conditions
				
			[ty Playground] Release / publish (push) Waiting to run
				
			
		
			
				
	
	
		
			385 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			385 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use std::{
 | |
|     path::{Path, PathBuf},
 | |
|     str::FromStr,
 | |
| };
 | |
| 
 | |
| use lsp_types::{
 | |
|     ClientCapabilities, LSPObject, NotebookDocumentCellChange, NotebookDocumentChangeTextContent,
 | |
|     Position, Range, TextDocumentContentChangeEvent, VersionedTextDocumentIdentifier,
 | |
| };
 | |
| use ruff_notebook::SourceValue;
 | |
| use ruff_server::{Client, ClientOptions, GlobalOptions, Workspace, Workspaces};
 | |
| 
 | |
| const SUPER_RESOLUTION_OVERVIEW_PATH: &str =
 | |
|     "./resources/test/fixtures/tensorflow_test_notebook.ipynb";
 | |
| 
 | |
| struct NotebookChange {
 | |
|     version: i32,
 | |
|     metadata: Option<LSPObject>,
 | |
|     updated_cells: lsp_types::NotebookDocumentCellChange,
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn super_resolution_overview() {
 | |
|     let file_path =
 | |
|         std::fs::canonicalize(PathBuf::from_str(SUPER_RESOLUTION_OVERVIEW_PATH).unwrap()).unwrap();
 | |
|     let file_url = lsp_types::Url::from_file_path(&file_path).unwrap();
 | |
|     let notebook = create_notebook(&file_path).unwrap();
 | |
| 
 | |
|     insta::assert_snapshot!("initial_notebook", notebook_source(¬ebook));
 | |
| 
 | |
|     let (main_loop_sender, main_loop_receiver) = crossbeam::channel::unbounded();
 | |
|     let (client_sender, client_receiver) = crossbeam::channel::unbounded();
 | |
| 
 | |
|     let client = Client::new(main_loop_sender, client_sender);
 | |
| 
 | |
|     let options = GlobalOptions::default();
 | |
|     let global = options.into_settings(client.clone());
 | |
| 
 | |
|     let mut session = ruff_server::Session::new(
 | |
|         &ClientCapabilities::default(),
 | |
|         ruff_server::PositionEncoding::UTF16,
 | |
|         global,
 | |
|         &Workspaces::new(vec![
 | |
|             Workspace::new(lsp_types::Url::from_file_path(file_path.parent().unwrap()).unwrap())
 | |
|                 .with_options(ClientOptions::default()),
 | |
|         ]),
 | |
|         &client,
 | |
|     )
 | |
|     .unwrap();
 | |
| 
 | |
|     session.open_notebook_document(file_url.clone(), notebook);
 | |
| 
 | |
|     let changes = [NotebookChange {
 | |
|         version: 0,
 | |
|         metadata: None,
 | |
|         updated_cells: NotebookDocumentCellChange {
 | |
|             structure: None,
 | |
|             data: None,
 | |
|             text_content: Some(vec![NotebookDocumentChangeTextContent {
 | |
|                 document: VersionedTextDocumentIdentifier {
 | |
|                     uri: make_cell_uri(&file_path, 5),
 | |
|                     version: 2,
 | |
|                 },
 | |
|                 changes: vec![
 | |
|                     TextDocumentContentChangeEvent {
 | |
|                         range: Some(Range {
 | |
|                             start: Position {
 | |
|                                 line: 18,
 | |
|                                 character: 61,
 | |
|                             },
 | |
|                             end: Position {
 | |
|                                 line: 18,
 | |
|                                 character: 62,
 | |
|                             },
 | |
|                         }),
 | |
|                         range_length: Some(1),
 | |
|                         text: "\"".to_string(),
 | |
|                     },
 | |
|                     TextDocumentContentChangeEvent {
 | |
|                         range: Some(Range {
 | |
|                             start: Position {
 | |
|                                 line: 18,
 | |
|                                 character: 55,
 | |
|                             },
 | |
|                             end: Position {
 | |
|                                 line: 18,
 | |
|                                 character: 56,
 | |
|                             },
 | |
|                         }),
 | |
|                         range_length: Some(1),
 | |
|                         text: "\"".to_string(),
 | |
|                     },
 | |
|                     TextDocumentContentChangeEvent {
 | |
|                         range: Some(Range {
 | |
|                             start: Position {
 | |
|                                 line: 14,
 | |
|                                 character: 46,
 | |
|                             },
 | |
|                             end: Position {
 | |
|                                 line: 14,
 | |
|                                 character: 47,
 | |
|                             },
 | |
|                         }),
 | |
|                         range_length: Some(1),
 | |
|                         text: "\"".to_string(),
 | |
|                     },
 | |
|                     TextDocumentContentChangeEvent {
 | |
|                         range: Some(Range {
 | |
|                             start: Position {
 | |
|                                 line: 14,
 | |
|                                 character: 40,
 | |
|                             },
 | |
|                             end: Position {
 | |
|                                 line: 14,
 | |
|                                 character: 41,
 | |
|                             },
 | |
|                         }),
 | |
|                         range_length: Some(1),
 | |
|                         text: "\"".to_string(),
 | |
|                     },
 | |
|                 ],
 | |
|             }]),
 | |
|         },
 | |
|     },
 | |
|     NotebookChange {
 | |
|         version: 1,
 | |
|         metadata: None,
 | |
|         updated_cells: NotebookDocumentCellChange {
 | |
|             structure: None,
 | |
|             data: None,
 | |
|             text_content: Some(vec![NotebookDocumentChangeTextContent {
 | |
|                 document: VersionedTextDocumentIdentifier {
 | |
|                     uri: make_cell_uri(&file_path, 4),
 | |
|                     version: 2
 | |
|                 },
 | |
|                 changes: vec![TextDocumentContentChangeEvent {
 | |
|                     range: Some(Range {
 | |
|                         start: Position {
 | |
|                             line: 0,
 | |
|                             character: 0
 | |
|                         },
 | |
|                         end: Position {
 | |
|                             line: 0,
 | |
|                             character: 181
 | |
|                         } }),
 | |
|                         range_length: Some(181),
 | |
|                         text: "test_img_path = tf.keras.utils.get_file(\n    \"lr.jpg\",\n    \"https://raw.githubusercontent.com/tensorflow/examples/master/lite/examples/super_resolution/android/app/src/main/assets/lr-1.jpg\",\n)".to_string()
 | |
|                     }
 | |
|                     ]
 | |
|                 }
 | |
|                 ]
 | |
|             )
 | |
|         }
 | |
|     },
 | |
|     NotebookChange {
 | |
|         version: 2,
 | |
|         metadata: None,
 | |
|         updated_cells: NotebookDocumentCellChange {
 | |
|             structure: None,
 | |
|             data: None,
 | |
|             text_content: Some(vec![NotebookDocumentChangeTextContent {
 | |
|                 document: VersionedTextDocumentIdentifier {
 | |
|                     uri: make_cell_uri(&file_path, 2),
 | |
|                     version: 2,
 | |
|                 },
 | |
|                 changes: vec![TextDocumentContentChangeEvent {
 | |
|                     range: Some(Range {
 | |
|                         start: Position {
 | |
|                             line: 3,
 | |
|                             character: 0,
 | |
|                         },
 | |
|                         end: Position {
 | |
|                             line: 3,
 | |
|                             character: 21,
 | |
|                         },
 | |
|                     }),
 | |
|                     range_length: Some(21),
 | |
|                     text: "\nprint(tf.__version__)".to_string(),
 | |
|                 }],
 | |
|             }]),
 | |
|         }
 | |
|     },
 | |
|     NotebookChange {
 | |
|         version: 3,
 | |
|         metadata: None,
 | |
|         updated_cells: NotebookDocumentCellChange {
 | |
|             structure: None,
 | |
|             data: None,
 | |
|             text_content: Some(vec![NotebookDocumentChangeTextContent {
 | |
|                 document: VersionedTextDocumentIdentifier {
 | |
|                     uri: make_cell_uri(&file_path, 1),
 | |
|                     version: 2,
 | |
|                 },
 | |
|                 changes: vec![TextDocumentContentChangeEvent {
 | |
|                     range: Some(Range {
 | |
|                         start: Position {
 | |
|                             line: 0,
 | |
|                             character: 0,
 | |
|                         },
 | |
|                         end: Position {
 | |
|                             line: 0,
 | |
|                             character: 49,
 | |
|                         },
 | |
|                     }),
 | |
|                     range_length: Some(49),
 | |
|                     text: "!pip install matplotlib tensorflow tensorflow-hub".to_string(),
 | |
|                 }],
 | |
|             }]),
 | |
|         },
 | |
|     },
 | |
|     NotebookChange {
 | |
|         version: 4,
 | |
|         metadata: None,
 | |
|         updated_cells: NotebookDocumentCellChange {
 | |
|             structure: None,
 | |
|             data: None,
 | |
|             text_content: Some(vec![NotebookDocumentChangeTextContent {
 | |
|                 document: VersionedTextDocumentIdentifier {
 | |
|                     uri: make_cell_uri(&file_path, 3),
 | |
|                     version: 2,
 | |
|                 },
 | |
|                 changes: vec![TextDocumentContentChangeEvent {
 | |
|                     range: Some(Range {
 | |
|                         start: Position {
 | |
|                             line: 3,
 | |
|                             character: 0,
 | |
|                         },
 | |
|                         end: Position {
 | |
|                             line: 15,
 | |
|                             character: 37,
 | |
|                         },
 | |
|                     }),
 | |
|                     range_length: Some(457),
 | |
|                     text: "\n@tf.function(input_signature=[tf.TensorSpec(shape=[1, 50, 50, 3], dtype=tf.float32)])\ndef f(input):\n    return concrete_func(input)\n\n\nconverter = tf.lite.TFLiteConverter.from_concrete_functions(\n    [f.get_concrete_function()], model\n)\nconverter.optimizations = [tf.lite.Optimize.DEFAULT]\ntflite_model = converter.convert()\n\n# Save the TF Lite model.\nwith tf.io.gfile.GFile(\"ESRGAN.tflite\", \"wb\") as f:\n    f.write(tflite_model)\n\nesrgan_model_path = \"./ESRGAN.tflite\"".to_string(),
 | |
|                 }],
 | |
|             }]),
 | |
|         },
 | |
|     },
 | |
|     NotebookChange {
 | |
|         version: 5,
 | |
|         metadata: None,
 | |
|         updated_cells: NotebookDocumentCellChange {
 | |
|             structure: None,
 | |
|             data: None,
 | |
|             text_content: Some(vec![NotebookDocumentChangeTextContent {
 | |
|                 document: VersionedTextDocumentIdentifier {
 | |
|                     uri: make_cell_uri(&file_path, 0),
 | |
|                     version: 2,
 | |
|                 },
 | |
|                 changes: vec![TextDocumentContentChangeEvent {
 | |
|                     range: Some(Range {
 | |
|                         start: Position {
 | |
|                             line: 0,
 | |
|                             character: 0,
 | |
|                         },
 | |
|                         end: Position {
 | |
|                             line: 2,
 | |
|                             character: 0,
 | |
|                         },
 | |
|                     }),
 | |
|                     range_length: Some(139),
 | |
|                     text: "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n".to_string(),
 | |
|                 }],
 | |
|             }]),
 | |
|         },
 | |
|     },
 | |
|     NotebookChange {
 | |
|         version: 6,
 | |
|         metadata: None,
 | |
|         updated_cells: NotebookDocumentCellChange {
 | |
|             structure: None,
 | |
|             data: None,
 | |
|             text_content: Some(vec![NotebookDocumentChangeTextContent {
 | |
|                 document: VersionedTextDocumentIdentifier {
 | |
|                     uri: make_cell_uri(&file_path, 6),
 | |
|                     version: 2,
 | |
|                 },
 | |
|                 changes: vec![TextDocumentContentChangeEvent {
 | |
|                     range: Some(Range {
 | |
|                         start: Position {
 | |
|                             line: 1,
 | |
|                             character: 0,
 | |
|                         },
 | |
|                         end: Position {
 | |
|                             line: 14,
 | |
|                             character: 28,
 | |
|                         },
 | |
|                     }),
 | |
|                     range_length: Some(361),
 | |
|                     text: "plt.figure(figsize=(1, 1))\nplt.title(\"LR\")\nplt.imshow(lr.numpy())\nplt.figure(figsize=(10, 4))\nplt.subplot(1, 2, 1)\nplt.title(f\"ESRGAN (x4)\")\nplt.imshow(sr.numpy())\nbicubic = tf.image.resize(lr, [200, 200], tf.image.ResizeMethod.BICUBIC)\nbicubic = tf.cast(bicubic, tf.uint8)\nplt.subplot(1, 2, 2)\nplt.title(\"Bicubic\")\nplt.imshow(bicubic.numpy());".to_string(),
 | |
|                 }],
 | |
|             }]),
 | |
|         },
 | |
|     }
 | |
|     ];
 | |
| 
 | |
|     let key = session.key_from_url(file_url.clone());
 | |
| 
 | |
|     for NotebookChange {
 | |
|         version,
 | |
|         metadata,
 | |
|         updated_cells,
 | |
|     } in changes
 | |
|     {
 | |
|         session
 | |
|             .update_notebook_document(&key, Some(updated_cells), metadata, version)
 | |
|             .unwrap();
 | |
|     }
 | |
| 
 | |
|     let snapshot = session.take_snapshot(file_url).unwrap();
 | |
| 
 | |
|     insta::assert_snapshot!(
 | |
|         "changed_notebook",
 | |
|         notebook_source(snapshot.query().as_notebook().unwrap())
 | |
|     );
 | |
| 
 | |
|     assert!(client_receiver.is_empty());
 | |
|     assert!(main_loop_receiver.is_empty());
 | |
| }
 | |
| 
 | |
| fn notebook_source(notebook: &ruff_server::NotebookDocument) -> String {
 | |
|     notebook.make_ruff_notebook().source_code().to_string()
 | |
| }
 | |
| 
 | |
| // produces an opaque URL based on a document path and a cell index
 | |
| fn make_cell_uri(path: &Path, index: usize) -> lsp_types::Url {
 | |
|     lsp_types::Url::parse(&format!(
 | |
|         "notebook-cell:///Users/test/notebooks/{}.ipynb?cell={index}",
 | |
|         path.file_name().unwrap().to_string_lossy()
 | |
|     ))
 | |
|     .unwrap()
 | |
| }
 | |
| 
 | |
| fn create_notebook(file_path: &Path) -> anyhow::Result<ruff_server::NotebookDocument> {
 | |
|     let ruff_notebook = ruff_notebook::Notebook::from_path(file_path)?;
 | |
| 
 | |
|     let mut cells = vec![];
 | |
|     let mut cell_documents = vec![];
 | |
|     for (i, cell) in ruff_notebook
 | |
|         .cells()
 | |
|         .iter()
 | |
|         .filter(|cell| cell.is_code_cell())
 | |
|         .enumerate()
 | |
|     {
 | |
|         let uri = make_cell_uri(file_path, i);
 | |
|         let (lsp_cell, cell_document) = cell_to_lsp_cell(cell, uri)?;
 | |
|         cells.push(lsp_cell);
 | |
|         cell_documents.push(cell_document);
 | |
|     }
 | |
| 
 | |
|     let serde_json::Value::Object(metadata) = serde_json::to_value(ruff_notebook.metadata())?
 | |
|     else {
 | |
|         anyhow::bail!("Notebook metadata was not an object");
 | |
|     };
 | |
| 
 | |
|     ruff_server::NotebookDocument::new(0, cells, metadata, cell_documents)
 | |
| }
 | |
| 
 | |
| fn cell_to_lsp_cell(
 | |
|     cell: &ruff_notebook::Cell,
 | |
|     cell_uri: lsp_types::Url,
 | |
| ) -> anyhow::Result<(lsp_types::NotebookCell, lsp_types::TextDocumentItem)> {
 | |
|     let contents = match cell.source() {
 | |
|         SourceValue::String(string) => string.clone(),
 | |
|         SourceValue::StringArray(array) => array.join(""),
 | |
|     };
 | |
|     let metadata = match serde_json::to_value(cell.metadata())? {
 | |
|         serde_json::Value::Null => None,
 | |
|         serde_json::Value::Object(metadata) => Some(metadata),
 | |
|         _ => anyhow::bail!("Notebook cell metadata was not an object"),
 | |
|     };
 | |
|     Ok((
 | |
|         lsp_types::NotebookCell {
 | |
|             kind: match cell {
 | |
|                 ruff_notebook::Cell::Code(_) => lsp_types::NotebookCellKind::Code,
 | |
|                 ruff_notebook::Cell::Markdown(_) => lsp_types::NotebookCellKind::Markup,
 | |
|                 ruff_notebook::Cell::Raw(_) => unreachable!(),
 | |
|             },
 | |
|             document: cell_uri.clone(),
 | |
|             metadata,
 | |
|             execution_summary: None,
 | |
|         },
 | |
|         lsp_types::TextDocumentItem::new(cell_uri, "python".to_string(), 1, contents),
 | |
|     ))
 | |
| }
 |