44import os
55import re
66import subprocess
7- import tempfile
87import textwrap
9- from contextlib import contextmanager
108from dataclasses import dataclass
11- from pathlib import Path
129from typing import List
1310
1411from collagraph .sfc .compiler import construct_ast
@@ -267,7 +264,7 @@ def run_ruff_format(
267264 source : str , * , use_single_quotes : bool = False , check : bool = False
268265) -> str :
269266 """
270- Format Python source code using ruff.
267+ Format Python source code using ruff via stdin .
271268
272269 Args:
273270 source: The Python source code to format
@@ -277,123 +274,105 @@ def run_ruff_format(
277274 Returns:
278275 Formatted Python source code
279276 """
280- ruff_command = [get_ruff_command (), "format" ]
277+ should_sort_imports = is_isort_configured ()
278+
279+ # Sort imports first if configured
280+ if should_sort_imports :
281+ import_sort_command = [
282+ get_ruff_command (),
283+ "check" ,
284+ "--select" ,
285+ "I" ,
286+ "--fix" ,
287+ "--stdin-filename" ,
288+ "source.py" ,
289+ ]
290+ result = subprocess .run (
291+ import_sort_command ,
292+ input = source ,
293+ capture_output = True ,
294+ text = True ,
295+ )
296+ # Use the fixed output if available, otherwise use original
297+ if result .returncode == 0 or result .stdout :
298+ source = result .stdout if result .stdout else source
299+
300+ # Build format command
301+ ruff_command = [
302+ get_ruff_command (),
303+ "format" ,
304+ "--stdin-filename" ,
305+ "source.py" ,
306+ ]
307+
281308 if check :
282309 ruff_command .append ("--check" )
283310
284- should_sort_imports = is_isort_configured ()
311+ # Configure quote style and indent width via inline TOML config
312+ if use_single_quotes :
313+ ruff_command .extend (
314+ [
315+ "--config" ,
316+ "format.quote-style = 'single'" ,
317+ "--config" ,
318+ "indent-width = 2" ,
319+ ]
320+ )
321+
322+ # Run ruff format with stdin
323+ result = subprocess .run (
324+ ruff_command ,
325+ input = source ,
326+ capture_output = True ,
327+ text = True ,
328+ )
285329
286- with tempfile .TemporaryDirectory () as directory :
287- target_file = Path (directory ) / "source.py"
288- target_file .write_text (source , encoding = "utf-8" )
289-
290- # Create config if single quotes requested
291- if use_single_quotes :
292- config_file = Path (directory ) / "ruff.toml"
293- config_file .write_text (
294- 'indent-width = 2\n [format]\n quote-style = "single"\n ' ,
295- encoding = "utf-8" ,
296- )
297- ruff_command .extend (["--config" , str (config_file )])
298-
299- ruff_command .append (str (target_file ))
300-
301- # Enable color output
302- env = os .environ .copy ()
303- env ["CLICOLOR_FORCE" ] = "1"
304-
305- # Run ruff
306- if should_sort_imports :
307- # Sort imports with: ruff check --select I --fix .
308- result = subprocess .run (
309- [
310- get_ruff_command (),
311- "check" ,
312- "--select" ,
313- "I" ,
314- "--fix" ,
315- str (target_file ),
316- ],
317- capture_output = True ,
318- text = True ,
319- env = env ,
320- )
321- # Then do the formatting
322- result = subprocess .run (ruff_command , capture_output = True , text = True , env = env )
323-
324- if result .returncode == 0 or not check :
325- return target_file .read_text (encoding = "utf-8" )
326- else :
327- # If check mode and would change, return original
328- return source
330+ if result .returncode == 0 or not check :
331+ # Format succeeded or not in check mode
332+ return result .stdout if result .stdout else source
333+ else :
334+ # If check mode and would change, return original
335+ return source
329336
330337
331338def run_ruff_check (
332339 source : str , fix : bool = False
333340) -> tuple [subprocess .CompletedProcess , str | None ]:
334341 """
335- Run ruff check on Python source code.
342+ Run ruff check on Python source code via stdin .
336343
337344 Args:
338345 source: The Python source code to check
339346 fix: Whether to apply fixes (default: False)
340347
341348 Returns:
342- Tuple of (CompletedProcess with the ruff result, temp file path,
349+ Tuple of (CompletedProcess with the ruff result,
343350 fixed content if fix=True else None)
344351 """
345- with temp_py_file (source ) as temp_path :
346- ruff_command = [
347- get_ruff_command (),
348- "check" ,
349- "--output-format=json" ,
350- "--no-cache" ,
351- "--ignore=RUF100" , # Ignore unused noqa (we add these for virtual render)
352- ]
353-
354- if fix :
355- ruff_command .append ("--fix" )
356-
357- ruff_command .append (str (temp_path ))
358-
359- env = os .environ .copy ()
360- env ["CLICOLOR_FORCE" ] = "1"
361-
362- result = subprocess .run (
363- ruff_command , capture_output = True , text = True , env = env , timeout = 30
364- )
365-
366- # If fix was requested, read back the fixed content
367- fixed_content = None
368- if fix :
369- fixed_content = temp_path .read_text (encoding = "utf-8" )
370-
371- return result , fixed_content
372-
373-
374- @contextmanager
375- def temp_py_file (content : str ):
376- """
377- Create a temporary Python file with the given content.
352+ ruff_command = [
353+ get_ruff_command (),
354+ "check" ,
355+ "--output-format=json" ,
356+ "--no-cache" ,
357+ "--ignore=RUF100" , # Ignore unused noqa (we add these for virtual render)
358+ "--stdin-filename" ,
359+ "source.py" ,
360+ ]
378361
379- Args :
380- content: The Python code to write to the file
362+ if fix :
363+ ruff_command . append ( "--fix" )
381364
382- Yields:
383- Path to the temporary file
365+ result = subprocess .run (
366+ ruff_command ,
367+ input = source ,
368+ capture_output = True ,
369+ text = True ,
370+ timeout = 30 ,
371+ )
384372
385- Example:
386- with temp_py_file("print('hello')") as path:
387- result = subprocess.run(['python', str(path)])
388- """
389- with tempfile .NamedTemporaryFile (mode = "w" , suffix = ".py" , delete = False ) as f :
390- f .write (content )
391- temp_path = Path (f .name )
373+ # If fix was requested, the fixed content is in stdout
374+ fixed_content = None
375+ if fix and result .stdout :
376+ fixed_content = result .stdout
392377
393- try :
394- yield temp_path
395- finally :
396- try :
397- temp_path .unlink ()
398- except Exception :
399- pass
378+ return result , fixed_content
0 commit comments