A JupyterLab extension to facilitate invocation of code formatters for multiple programming languages.
—
Extensible code formatter system supporting multiple programming languages and formatter tools with configurable options, magic command handling, and error management.
Abstract base class defining the formatter interface.
class BaseFormatter(abc.ABC):
@property
@abc.abstractmethod
def label(self) -> str:
"""Human-readable formatter name"""
pass
@property
@abc.abstractmethod
def importable(self) -> bool:
"""Whether formatter dependencies are available"""
pass
@abc.abstractmethod
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Format code with specified options"""
pass
@property
def cached_importable(self) -> bool:
"""Cached version of importable check"""
return self.importablePython code formatter using Black.
class BlackFormatter(BaseFormatter):
label = "Apply Black Formatter"
@property
def importable(self) -> bool:
"""Check if black is available"""
pass
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Format code using Black"""
passSupported Options:
line_length (int) - Maximum line lengthstring_normalization (bool) - Normalize string quotesmagic_trailing_comma (bool) - Use trailing commasexperimental_string_processing (bool) - Enable experimental featurespreview (bool) - Enable preview featuresPython code formatter using Blue (Black fork).
class BlueFormatter(BaseFormatter):
label = "Apply Blue Formatter"
@property
def importable(self) -> bool:
"""Check if blue is available"""
pass
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Format code using Blue"""
passPython code formatter using autopep8.
class Autopep8Formatter(BaseFormatter):
label = "Apply Autopep8 Formatter"
@property
def importable(self) -> bool:
"""Check if autopep8 is available"""
pass
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Format code using autopep8"""
passPython code formatter using YAPF.
class YapfFormatter(BaseFormatter):
label = "Apply YAPF Formatter"
@property
def importable(self) -> bool:
"""Check if yapf is available"""
pass
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Format code using YAPF"""
passPython import sorter using isort.
class IsortFormatter(BaseFormatter):
label = "Apply Isort Formatter"
@property
def importable(self) -> bool:
"""Check if isort is available"""
pass
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Sort imports using isort"""
passPython linter/formatter using Ruff.
class RuffFixFormatter(CommandLineFormatter):
label = "Apply ruff fix"
def __init__(self):
"""Initialize with ruff fix command"""
pass
class RuffFormatFormatter(RuffFixFormatter):
label = "Apply ruff formatter"
def __init__(self):
"""Initialize with ruff format command"""
passR code formatter using formatR package.
class FormatRFormatter(RFormatter):
label = "Apply FormatR Formatter"
package_name = "formatR"
@property
def importable(self) -> bool:
"""Check if formatR package is available"""
pass
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Format R code using formatR"""
passR code formatter using styler package.
class StylerFormatter(RFormatter):
label = "Apply Styler Formatter"
package_name = "styler"
@property
def importable(self) -> bool:
"""Check if styler package is available"""
pass
def format_code(self, code: str, notebook: bool, **options) -> str:
"""Format R code using styler"""
passWrapper for command-line formatters.
class CommandLineFormatter(BaseFormatter):
command: List[str]
def __init__(self, command: List[str]):
"""Initialize with command list"""
self.command = command
@property
def label(self) -> str:
"""Generate label from command name"""
return f"Apply {self.command[0]} Formatter"
@property
def importable(self) -> bool:
"""Check if command exists"""
pass
def format_code(self, code: str, notebook: bool, args: List[str] = [], **options) -> str:
"""Format code using command line tool"""
passAbstract base class for handling special syntax.
class BaseLineEscaper(abc.ABC):
def __init__(self, code: str) -> None:
self.code = code
@property
@abc.abstractmethod
def langs(self) -> List[str]:
"""Supported programming languages"""
pass
@abc.abstractmethod
def escape(self, line: str) -> str:
"""Escape special syntax before formatting"""
pass
@abc.abstractmethod
def unescape(self, line: str) -> str:
"""Restore special syntax after formatting"""
passclass MagicCommandEscaper(BaseLineEscaper):
"""Handles Jupyter magic commands (% and %%)"""
langs = ["python"]
class HelpEscaper(BaseLineEscaper):
"""Handles help commands (? and ??)"""
langs = ["python"]
class CommandEscaper(BaseLineEscaper):
"""Handles shell commands (!)"""
langs = ["python"]
class QuartoCommentEscaper(BaseLineEscaper):
"""Handles Quarto comments (#|)"""
langs = ["python"]
class RunScriptEscaper(BaseLineEscaper):
"""Handles run script commands"""
langs = ["python"]Global registry of all available formatters.
SERVER_FORMATTERS: Dict[str, BaseFormatter] = {
"black": BlackFormatter(),
"blue": BlueFormatter(),
"autopep8": Autopep8Formatter(),
"yapf": YapfFormatter(),
"isort": IsortFormatter(),
"ruff": RuffFixFormatter(),
"ruffformat": RuffFormatFormatter(),
"formatR": FormatRFormatter(),
"styler": StylerFormatter(),
"scalafmt": CommandLineFormatter(command=["scalafmt", "--stdin"]),
"rustfmt": CommandLineFormatter(command=["rustfmt"]),
"astyle": CommandLineFormatter(command=["astyle"]),
}List of all available line escaper classes.
ESCAPER_CLASSES: List[Type[BaseLineEscaper]] = [
MagicCommandEscaper,
HelpEscaper,
CommandEscaper,
QuartoCommentEscaper,
RunScriptEscaper,
]from jupyterlab_code_formatter.formatters import BlackFormatter, IsortFormatter
# Create formatter instances
black_formatter = BlackFormatter()
isort_formatter = IsortFormatter()
# Check availability
if black_formatter.importable:
# Format code with options
formatted_code = black_formatter.format_code(
code="def hello( ):\n pass",
notebook=True,
line_length=88,
string_normalization=True
)
print(formatted_code) # "def hello():\n pass"
# Format imports
if isort_formatter.importable:
formatted_imports = isort_formatter.format_code(
code="import os\nimport sys\nimport numpy",
notebook=False,
multi_line_output=3,
include_trailing_comma=True
)from jupyterlab_code_formatter.formatters import CommandLineFormatter
# Create Rust formatter
rustfmt = CommandLineFormatter(command=["rustfmt"])
# Check if rustfmt command exists
if rustfmt.importable:
formatted_rust = rustfmt.format_code(
code="fn main(){println!(\"Hello\");}",
notebook=False,
args=["--edition", "2021"]
)from jupyterlab_code_formatter.formatters import StylerFormatter
# Create styler formatter
styler = StylerFormatter()
# Check if R and styler package are available
if styler.importable:
formatted_r = styler.format_code(
code="x<-c(1,2,3)\ny<-mean(x)",
notebook=True,
scope="tokens",
indent_by=2
)from jupyterlab_code_formatter.formatters import BaseFormatter
import subprocess
class CustomFormatter(BaseFormatter):
@property
def label(self) -> str:
return "Apply Custom Formatter"
@property
def importable(self) -> bool:
# Check if custom formatter is available
return shutil.which("custom-formatter") is not None
def format_code(self, code: str, notebook: bool, **options) -> str:
# Custom formatting logic
process = subprocess.run(
["custom-formatter", "--stdin"],
input=code,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
if process.stderr:
raise Exception(f"Formatter error: {process.stderr}")
return process.stdout
# Register custom formatter
from jupyterlab_code_formatter.formatters import SERVER_FORMATTERS
SERVER_FORMATTERS["custom"] = CustomFormatter()def is_importable(pkg_name: str) -> bool:
"""Check if Python package is importable"""
pass
def command_exist(name: str) -> bool:
"""Check if command-line tool exists"""
passdef import_black():
"""Import black with Blue compatibility handling"""
pass
def import_blue():
"""Import blue and perform monkey patching"""
passdef handle_line_ending_and_magic(func):
"""Decorator for handling magic commands and line endings"""
pass# Black formatter options
black_options = {
"line_length": 88,
"string_normalization": True,
"magic_trailing_comma": True,
"experimental_string_processing": False,
"preview": False
}
# YAPF formatter options
yapf_options = {
"based_on_style": "pep8",
"column_limit": 88,
"dedent_closing_brackets": True,
"indent_width": 4
}
# Isort formatter options
isort_options = {
"multi_line_output": 3,
"include_trailing_comma": True,
"force_grid_wrap": 0,
"use_parentheses": True,
"line_length": 88
}Supported Languages and Formatters:
Extensibility: New formatters can be added by implementing BaseFormatter or using CommandLineFormatter for command-line tools.
Install with Tessl CLI
npx tessl i tessl/pypi-jupyterlab-code-formatter