Skip to content

Commit 07f0478

Browse files
authored
Suppress stderr in call to ruff and add ruff formatter (#333)
* suppress stderr in call to ruff * add separate ruffformat options to schema * add tests for ruff fix and format * add ruff as a test dependency
1 parent 7cead40 commit 07f0478

File tree

4 files changed

+84
-9
lines changed

4 files changed

+84
-9
lines changed

jupyterlab_code_formatter/formatters.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,9 +456,11 @@ def format_code(self, code: str, notebook: bool, args: List[str] = [], **options
456456

457457

458458
class RuffFixFormatter(CommandLineFormatter):
459+
ruff_args = ["check", "-eq", "--fix-only", "-"]
460+
459461
@property
460462
def label(self) -> str:
461-
return f"Apply ruff Formatter"
463+
return "Apply ruff fix"
462464

463465
def __init__(self):
464466
try:
@@ -467,7 +469,15 @@ def __init__(self):
467469
ruff_command = find_ruff_bin()
468470
except (ImportError, FileNotFoundError):
469471
ruff_command = "ruff"
470-
self.command = [ruff_command, "check", "--fix-only", "-"]
472+
self.command = [ruff_command, *self.ruff_args]
473+
474+
475+
class RuffFormatFormatter(RuffFixFormatter):
476+
@property
477+
def label(self) -> str:
478+
return "Apply ruff formatter"
479+
480+
ruff_args = ["format", "-q", "-"]
471481

472482

473483
SERVER_FORMATTERS = {
@@ -477,6 +487,7 @@ def __init__(self):
477487
"yapf": YapfFormatter(),
478488
"isort": IsortFormatter(),
479489
"ruff": RuffFixFormatter(),
490+
"ruffformat": RuffFormatFormatter(),
480491
"formatR": FormatRFormatter(),
481492
"styler": StylerFormatter(),
482493
"scalafmt": CommandLineFormatter(command=["scalafmt", "--stdin"]),

jupyterlab_code_formatter/tests/test_handlers.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -588,11 +588,15 @@ async def test_can_rustfmt(request_format): # type: ignore[no-untyped-def]
588588
assert json_result["code"][0]["code"] == expected
589589

590590

591-
@pytest.mark.xfail(reason="Rust toolchain isn't respected in test for some reason atm.")
592-
async def test_can_apply_ruff(request_format): # type: ignore[no-untyped-def]
593-
"""Check that it can apply black with simple config."""
591+
IMPORT_SORTING_EXAMPLE = (
592+
"import numpy as np\nimport sys,os\nfrom enum import IntEnum\nfrom enum import auto"
593+
)
594+
595+
596+
async def test_can_apply_ruff_formatter(request_format): # type: ignore[no-untyped-def]
597+
"""Check that it can apply ruff with simple config."""
594598
response: HTTPResponse = await request_format(
595-
formatter="ruff",
599+
formatter="ruffformat",
596600
code=[SIMPLE_VALID_PYTHON_CODE],
597601
options={},
598602
)
@@ -602,3 +606,47 @@ async def test_can_apply_ruff(request_format): # type: ignore[no-untyped-def]
602606
expected_schema=EXPECTED_FROMAT_SCHEMA,
603607
)
604608
assert json_result["code"][0]["code"] == "x = 22\ne = 1"
609+
610+
611+
async def test_can_apply_ruff_import_fix(request_format): # type: ignore[no-untyped-def]
612+
"""Check that it can organize imports with ruff."""
613+
614+
given = "import foo\nimport numpy as np\nimport sys,os\nfrom enum import IntEnum\nfrom enum import auto"
615+
expected = "import os\nimport sys\nfrom enum import IntEnum, auto\n\nimport numpy as np\n\nimport foo"
616+
response: HTTPResponse = await request_format(
617+
formatter="ruff",
618+
code=[given],
619+
options={
620+
"args": [
621+
"--select=I001",
622+
"--config",
623+
"lint.isort.known-first-party=['foo']",
624+
]
625+
},
626+
)
627+
json_result = _check_http_code_and_schema(
628+
response=response,
629+
expected_code=200,
630+
expected_schema=EXPECTED_FROMAT_SCHEMA,
631+
)
632+
assert json_result["code"][0]["code"] == expected
633+
634+
635+
async def test_can_apply_ruff_fix_unsafe(request_format): # type: ignore[no-untyped-def]
636+
"""Check that it can apply unsafe fixes."""
637+
638+
given = """if arg != None:
639+
pass"""
640+
expected = """if arg is not None:
641+
pass"""
642+
response: HTTPResponse = await request_format(
643+
formatter="ruff",
644+
code=[given],
645+
options={"args": ["--select=E711", "--unsafe-fixes"]},
646+
)
647+
json_result = _check_http_code_and_schema(
648+
response=response,
649+
expected_code=200,
650+
expected_schema=EXPECTED_FROMAT_SCHEMA,
651+
)
652+
assert json_result["code"][0]["code"] == expected

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ test = [
5353
"yapf",
5454
"rpy2",
5555
"importlib_metadata; python_version<'3.8'",
56+
"ruff",
5657
]
5758

5859
[tool.hatch.version]

schema/settings.json

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,13 @@
208208
"additionalProperties": false,
209209
"type": "object"
210210
},
211+
"ruffformat": {
212+
"properties": {
213+
"args": { "type": "array", "items": { "type": "string" } }
214+
},
215+
"additionalProperties": false,
216+
"type": "object"
217+
},
211218
"formatR": {
212219
"properties": {
213220
"comment": {
@@ -407,11 +414,19 @@
407414
}
408415
},
409416
"ruff": {
410-
"title": "Ruff Config",
411-
"description": "Command line options to be passed to ruff.",
417+
"title": "Ruff Check Config",
418+
"description": "Command line options to be passed to ruff check. Default is to organise imports.",
412419
"$ref": "#/definitions/ruff",
413420
"default": {
414-
"args": ["--select=I"]
421+
"args": ["--select=I001"]
422+
}
423+
},
424+
"ruffformat": {
425+
"title": "Ruff Format Config",
426+
"description": "Command line options to be passed to ruff format.",
427+
"$ref": "#/definitions/ruffformat",
428+
"default": {
429+
"args": []
415430
}
416431
},
417432
"suppressFormatterErrors": {

0 commit comments

Comments
 (0)