diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..48adc9c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,29 @@ +name: Tests + +on: + push: + branches: + - main + pull_request: + +jobs: + pytest: + name: pytest (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12"] + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install test dependencies + # comfy_api is mocked in conftest.py, so a full ComfyUI install isn't needed. + # numpy silences torch's "Failed to initialize NumPy" import warning. + run: python -m pip install --upgrade pip pytest torch numpy + - name: Run tests + run: python -m pytest -q diff --git a/nodes.py b/nodes.py index d9dd8e1..50b4ec6 100644 --- a/nodes.py +++ b/nodes.py @@ -393,6 +393,29 @@ class ConstrainResolution(io.ComfyNode): width, height, min_res, max_res, multiple_of, constraint_mode ) + # Degenerate input (empty/malformed tensor) collapses to a 0 target, + # which would crash the resizer. Pass the image through untouched instead. + if target_width == 0 or target_height == 0: + logger.warning( + "Input has a zero dimension (%dx%d); passing image through unchanged.", + width, height + ) + return io.NodeOutput( + image, image, width, height, + original_aspect_ratio, original_aspect_ratio + ) + + # Warn when Prioritize Min Resolution forces a large upscale (extreme aspect + # ratios can blow up the long side and risk OOM). Strict mode caps this instead. + if constraint_mode == ConstraintMode.MIN_RES.value: + upscale_factor = max(target_width / width, target_height / height) + if upscale_factor > 4: + logger.warning( + "Upscaling by %.1fx to %dx%d to satisfy min_res on an extreme aspect ratio. " + "Use 'Prioritize Max Resolution (Strict)' to cap output size and avoid large upscales.", + upscale_factor, target_width, target_height + ) + # Resize image to target dimensions resized_image = cls.resize_image(image, target_width, target_height, resize_method) diff --git a/tests/test_nodes.py b/tests/test_nodes.py index 6ae40bd..126ccb7 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -180,3 +180,27 @@ class TestCropImage: image = torch.rand(1, 120, 200, 3) out = ConstrainResolution.crop_image(image, 100, 100, position) assert out.shape == (1, 100, 100, 3) + + +class TestExecuteGuards: + def test_zero_dimension_input_passes_through(self): + """A malformed tensor with a zero dimension must pass through, not crash the resizer.""" + image = torch.rand(1, 0, 500, 3) + resized, original, out_w, out_h, _, _ = run_node(image) + assert resized.shape == image.shape + assert original.shape == image.shape + assert (out_w, out_h) == (500, 0) + + def test_extreme_ratio_min_res_warns(self, caplog): + """Extreme aspect ratio in MIN_RES mode should warn about the large upscale.""" + image = torch.rand(1, 100, 1000, 3) + with caplog.at_level("WARNING"): + run_node(image, constraint_mode=MIN) + assert any("Upscaling by" in r.message for r in caplog.records) + + def test_normal_image_does_not_warn(self, caplog): + """A normal image must not trigger the upscale warning.""" + image = torch.rand(1, 800, 1000, 3) + with caplog.at_level("WARNING"): + run_node(image, constraint_mode=MIN) + assert not any("Upscaling by" in r.message for r in caplog.records)