diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 402302f..a61c531 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -34,6 +34,6 @@ jobs: path: ./dist - name: Install run: | - pip install `echo dist/*.whl`[dev] "black<23" + pip install `echo dist/*.whl`[dev] - name: test run: pytest --cov=reacton reacton diff --git a/pyproject.toml b/pyproject.toml index 2586581..3232f26 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,6 @@ packages = ["react_ipywidgets", "reacton"] [project.optional-dependencies] dev = [ "ruff; python_version > '3.6'", - "black", "mypy", "pre-commit", "coverage", diff --git a/reacton/generate.py b/reacton/generate.py index 858d549..9fc7ea9 100644 --- a/reacton/generate.py +++ b/reacton/generate.py @@ -5,7 +5,6 @@ from textwrap import indent from typing import Any, Dict, Generic, Type, TypeVar -import black import bqplot import ipywidgets import ipywidgets as widgets # type: ignore @@ -106,9 +105,28 @@ def get_element_class(self, cls): def get_ignore_props(self, cls): return self.ignore_props + # Replicated from https://gist.github.com/shner-elmo/b2639a4d1e04ceafaad120acfb31213c + def ruff_format(self, code: str) -> str: + import subprocess + from ruff.__main__ import find_ruff_bin + + ruff_args = [ + find_ruff_bin(), + "format", + "--stdin-filename", + "foo.py", # you can pass any random string, it wont use it... + # these two lines are optional, but this is how you can pass the config for ruff + "--line-length", + f"{MAX_LINE_LENGTH}", + ] + proc = subprocess.run(ruff_args, input=code, text=True, capture_output=True) + proc.check_returncode() # raise an Exception if return code is not 0 + return proc.stdout + def generate_component(self, cls: Type[widgets.Widget], blacken=True): element_class_name = self.get_element_class(cls).__name__ ignore = self.get_ignore_props(cls) + traits = {key: value for key, value in cls.class_traits().items() if "output" not in value.metadata and not key.startswith("_") and key not in ignore} def has_default(trait): @@ -293,9 +311,8 @@ def {{ method_name }}(**kwargs): ) if blacken: - mode = black.Mode(line_length=MAX_LINE_LENGTH) try: - code = black.format_file_contents(code, fast=False, mode=mode) + code = self.ruff_format(code) except Exception: print("code:\n", code) raise @@ -325,10 +342,7 @@ def generate(self, path, blacken=True): raise ValueError(f"Could not find new line after marker: {marker!r}") code_total = current_code[: start + 1] + "\n" + code if blacken: - import black - - mode = black.Mode(line_length=MAX_LINE_LENGTH) - code_total = black.format_file_contents(code_total, fast=False, mode=mode) + code_total = self.ruff_format(code_total) only_valid = True if only_valid: try: diff --git a/reacton/generate_test.py b/reacton/generate_test.py index e7998fb..64bb62c 100644 --- a/reacton/generate_test.py +++ b/reacton/generate_test.py @@ -1,9 +1,12 @@ +import sys import ipywidgets as widgets import traitlets +import pytest from .generate import CodeGen +@pytest.mark.skipif(sys.version_info < (3, 7), reason="Ruff does not support Python < 3.7") def test_basic(): class MyTest(traitlets.HasTraits): a = traitlets.traitlets.Int(1) @@ -22,7 +25,6 @@ def _MyTest( @implements(_MyTest) def MyTest(**kwargs): - widget_cls = reacton.generate_test.MyTest comp = reacton.core.ComponentWidget(widget=widget_cls) return Element(comp, kwargs=kwargs) @@ -33,6 +35,7 @@ def MyTest(**kwargs): assert code.strip() == code_expected.strip() +@pytest.mark.skipif(sys.version_info < (3, 7), reason="Ruff does not support Python < 3.7") def test_value(): class MyTest(traitlets.HasTraits): a = traitlets.traitlets.Int(1) @@ -51,7 +54,6 @@ def _MyTest( @implements(_MyTest) def MyTest(**kwargs): - widget_cls = reacton.generate_test.MyTest comp = reacton.core.ComponentWidget(widget=widget_cls) return ValueElement("value", comp, kwargs=kwargs) @@ -62,6 +64,7 @@ def MyTest(**kwargs): assert code.strip() == code_expected.strip() +@pytest.mark.skipif(sys.version_info < (3, 7), reason="Ruff does not support Python < 3.7") def test_instance_non_widget(): class NonWidget: def __init__(self, *args) -> None: @@ -85,7 +88,6 @@ def _MyTest( @implements(_MyTest) def MyTest(**kwargs): - widget_cls = reacton.generate_test.MyTest comp = reacton.core.ComponentWidget(widget=widget_cls) return Element(comp, kwargs=kwargs) @@ -95,6 +97,7 @@ def MyTest(**kwargs): assert code.strip() == code_expected.strip() +@pytest.mark.skipif(sys.version_info < (3, 7), reason="Ruff does not support Python < 3.7") def test_instance_widget(): class SomeWidget(widgets.Widget): def __init__(self, *args) -> None: @@ -116,7 +119,6 @@ def _MyTest( @implements(_MyTest) def MyTest(**kwargs): - widget_cls = reacton.generate_test.MyTest comp = reacton.core.ComponentWidget(widget=widget_cls) return Element(comp, kwargs=kwargs)