From daea622680cc32d74578d1a49a84322475f2c239 Mon Sep 17 00:00:00 2001 From: Dominik Breksa Date: Tue, 9 Dec 2025 10:38:48 +0100 Subject: [PATCH 1/6] fix: fixed linters so all tests should pass --- Makefile | 1 - src/python/app/command/parser.py | 16 ++++++++++++++-- src/python/app/imcli.py | 3 +++ src/python/app/io/bmp.py | 6 ++++-- src/python/app/io/format_factory.py | 6 +++--- src/python/app/io/format_reader.py | 2 -- .../app/operation/histogram_equalization.py | 2 +- src/python/app/operation/operation.py | 3 --- 8 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index ec2a6d8..65850dd 100644 --- a/Makefile +++ b/Makefile @@ -18,4 +18,3 @@ ruff: flake8: flake8 ./src/python/ - diff --git a/src/python/app/command/parser.py b/src/python/app/command/parser.py index 48fe02e..5d06ef8 100644 --- a/src/python/app/command/parser.py +++ b/src/python/app/command/parser.py @@ -34,8 +34,7 @@ def get_parser() -> ArgumentParser: subparser = parser.add_subparsers(required=True, help='Command to be performed on an image') - operation_class: type[Operation] - for operation_class in [Rotate90Operation, IdentityOperation, FlipOperation, BGR2RGBOperation, RollOperation, GrayscaleOperation, HistogramEqualizationOperation]: + for operation_class in available_commands(): operation = operation_class() operation_parser = subparser.add_parser(name=operation_class.name(), @@ -46,6 +45,7 @@ def get_parser() -> ArgumentParser: return parser + def prepare_command(command: Operation) -> Callable[[Namespace], int]: def wrapper(args: Namespace) -> int: @@ -61,3 +61,15 @@ def wrapper(args: Namespace) -> int: return 0 return wrapper + + +def available_commands(): + return [ + Rotate90Operation, + IdentityOperation, + FlipOperation, + BGR2RGBOperation, + RollOperation, + GrayscaleOperation, + HistogramEqualizationOperation, + ] diff --git a/src/python/app/imcli.py b/src/python/app/imcli.py index 0aeeaa4..a6f1346 100644 --- a/src/python/app/imcli.py +++ b/src/python/app/imcli.py @@ -1,3 +1,5 @@ +"""Main entrypoint for imcli program""" + from app.command.parser import get_parser @@ -5,5 +7,6 @@ def main() -> None: args = get_parser().parse_args() return args.func(args) + if __name__ == '__main__': main() diff --git a/src/python/app/io/bmp.py b/src/python/app/io/bmp.py index 44dc20d..8f8cb71 100644 --- a/src/python/app/io/bmp.py +++ b/src/python/app/io/bmp.py @@ -46,7 +46,8 @@ def read_format(self, file: BinaryIO) -> Image: assert panes == 1 assert bits_per_pixel in (1, 4, 8, 16, 24, 32) - compression_method, raw_bitmap_data_size, horizontal_resolution, vertical_resolution, num_colors, num_important_colors = \ + compression_method, raw_bitmap_data_size, horizontal_resolution, vertical_resolution, \ + num_colors, num_important_colors = \ struct.unpack('IIiiII', dib_header_no_size[12:]) assert compression_method == 0 assert raw_bitmap_data_size != 0 @@ -61,7 +62,8 @@ def read_format(self, file: BinaryIO) -> Image: num_colors_end = bits_per_pixel // 8 return Image(data=np.flip( np.flip( - np.frombuffer(bytes(image_bytes), dtype=np.uint8).reshape(image_height, image_width, num_colors_end)[:, :, ::-1], + np.frombuffer(bytes(image_bytes), + dtype=np.uint8).reshape(image_height, image_width, num_colors_end)[:, :, ::-1], axis=0 ), axis=1) diff --git a/src/python/app/io/format_factory.py b/src/python/app/io/format_factory.py index 85ac265..b9373cb 100644 --- a/src/python/app/io/format_factory.py +++ b/src/python/app/io/format_factory.py @@ -1,5 +1,4 @@ import enum -from typing import Self from app.error.unknown_format_exception import UnknownFormatException from app.io.bmp import BMPReader, BMPWriter @@ -11,7 +10,7 @@ class KnownFormat(enum.Enum): BMP = 0 @classmethod - def from_string(cls, data_format: str) -> Self: + def from_string(cls, data_format: str) -> 'KnownFormat': match data_format: case 'bmp': return cls.BMP @@ -24,7 +23,7 @@ def get_available_formats(cls) -> list[str]: return [e.name.lower() for e in cls] @classmethod - def default(cls) -> Self: + def default(cls) -> 'KnownFormat': return KnownFormat.BMP @@ -37,6 +36,7 @@ def get_reader_from_format(data_format: KnownFormat) -> FormatReader: case _: assert False, "unreachable" + def get_writer_from_format(data_format: KnownFormat) -> FormatWriter: match data_format: diff --git a/src/python/app/io/format_reader.py b/src/python/app/io/format_reader.py index 73dd446..e95f6f0 100644 --- a/src/python/app/io/format_reader.py +++ b/src/python/app/io/format_reader.py @@ -1,8 +1,6 @@ from abc import abstractmethod, ABC from typing import BinaryIO -import numpy as np - from app.image.image import Image diff --git a/src/python/app/operation/histogram_equalization.py b/src/python/app/operation/histogram_equalization.py index b203f32..66961e7 100644 --- a/src/python/app/operation/histogram_equalization.py +++ b/src/python/app/operation/histogram_equalization.py @@ -37,4 +37,4 @@ def equalize_chanel(self, image: np.ndarray) -> np.ndarray: cdf = (256 - 1) * cdf / cdf[-1] image_equalized = np.interp(image.flatten(), bins[:-1], cdf) - return image_equalized.reshape(image.shape) \ No newline at end of file + return image_equalized.reshape(image.shape) diff --git a/src/python/app/operation/operation.py b/src/python/app/operation/operation.py index 5e233a7..c605a28 100644 --- a/src/python/app/operation/operation.py +++ b/src/python/app/operation/operation.py @@ -1,8 +1,5 @@ from abc import ABC, abstractmethod from argparse import Namespace, ArgumentParser -from typing import final - -import numpy as np from app.image.image import Image From 5f85a11d0f8111b7f8b648c9f32eefcafce0d295 Mon Sep 17 00:00:00 2001 From: Dominik Breksa Date: Tue, 9 Dec 2025 10:42:30 +0100 Subject: [PATCH 2/6] fix: cpp linter --- src/cpp/fast/foo.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/cpp/fast/foo.cpp b/src/cpp/fast/foo.cpp index 2b1f510..d7f9e19 100644 --- a/src/cpp/fast/foo.cpp +++ b/src/cpp/fast/foo.cpp @@ -9,19 +9,25 @@ numpy_system(PyObject *self, PyObject *args) int sts; if (!PyArg_ParseTuple(args, "s", &command)) + { return NULL; + } + sts = system(command); return PyLong_FromLong(sts); } static PyObject * -numpy_add(PyObject *self, PyObject *args){ +numpy_add(PyObject *self, PyObject *args) +{ PyArrayObject *arr; PyArg_ParseTuple(args, "O", &arr); - if(PyErr_Occurred()){ + if(PyErr_Occurred()) + { return NULL; } - if(!PyArray_Check(arr) || PyArray_TYPE(arr) != NPY_DOUBLE) { + if(!PyArray_Check(arr) || PyArray_TYPE(arr) != NPY_DOUBLE) + { PyErr_SetString(PyExc_TypeError, "Argument must be a numpy array of type double!"); return NULL; } @@ -31,9 +37,11 @@ numpy_add(PyObject *self, PyObject *args){ int64_t size = PyArray_SIZE(arr); double total=0; - for (int i=0; i < size; i++){ + for (int i=0; i < size; i++) + { total += data[i]; } + return PyFloat_FromDouble(total); } @@ -42,13 +50,15 @@ static PyObject *SpamError = NULL; static int numpy_module_exec(PyObject *m) { - if (SpamError != NULL) { + if (SpamError != NULL) + { PyErr_SetString(PyExc_ImportError, "cannot initialize numpy module more than once"); return -1; } SpamError = PyErr_NewException("numpy.error", NULL, NULL); - if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) { + if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) + { return -1; } From 6296566c09e340662b0207659b2662a1a8cb85e5 Mon Sep 17 00:00:00 2001 From: Dominik Breksa Date: Tue, 9 Dec 2025 10:48:57 +0100 Subject: [PATCH 3/6] fix: linters --- .github/workflows/cpp_linters.yaml | 2 +- src/cpp/fast/foo.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cpp_linters.yaml b/.github/workflows/cpp_linters.yaml index b8be389..3e527ad 100644 --- a/.github/workflows/cpp_linters.yaml +++ b/.github/workflows/cpp_linters.yaml @@ -31,4 +31,4 @@ jobs: - name: Install cpplint run: pipx install cpplint - name: Run cpplint - run: cpplint --filter=-whitespace/line_length,-whitespace/parens ./src/cpp/fast/* + run: cpplint --filter=-whitespace/braces --linelength=120 ./src/cpp/fast/* diff --git a/src/cpp/fast/foo.cpp b/src/cpp/fast/foo.cpp index d7f9e19..dd933e6 100644 --- a/src/cpp/fast/foo.cpp +++ b/src/cpp/fast/foo.cpp @@ -33,11 +33,11 @@ numpy_add(PyObject *self, PyObject *args) } - double *data = (double *) PyArray_DATA(arr); + double *data = reinterpret_cast(PyArray_DATA(arr)); int64_t size = PyArray_SIZE(arr); - double total=0; - for (int i=0; i < size; i++) + double total = 0; + for (int i = 0; i < size; i++) { total += data[i]; } @@ -72,7 +72,7 @@ static PyMethodDef numpy_methods[] = { }; static PyModuleDef_Slot numpy_module_slots[] = { - {Py_mod_exec, (void*) numpy_module_exec}, + {Py_mod_exec, reinterpret_cast(numpy_module_exec)}, {0, NULL} }; @@ -90,4 +90,4 @@ PyInit_fast(void) PyObject* module_obj = PyModuleDef_Init(&numpy_module); import_array(); return module_obj; -} \ No newline at end of file +} From 8bbc5a6650625e438c744484aeaacd6ff7b5254f Mon Sep 17 00:00:00 2001 From: Dominik Breksa Date: Sun, 14 Dec 2025 19:23:58 +0100 Subject: [PATCH 4/6] feat: added clang-tidy --- .github/workflows/cpp_linters.yaml | 14 +++----------- Makefile | 3 +++ src/cpp/fast/foo.cpp | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.github/workflows/cpp_linters.yaml b/.github/workflows/cpp_linters.yaml index 3e527ad..7bb97fd 100644 --- a/.github/workflows/cpp_linters.yaml +++ b/.github/workflows/cpp_linters.yaml @@ -20,15 +20,7 @@ jobs: python-version: 3.13 - name: Install libraries - run: make python-install-editable + run: make python-install-development - - name: Install pipx - run: | - sudo apt update - sudo apt install pipx - pipx ensurepath - sudo pipx ensurepath --global - - name: Install cpplint - run: pipx install cpplint - - name: Run cpplint - run: cpplint --filter=-whitespace/braces --linelength=120 ./src/cpp/fast/* + - name: clang-tidy + run: make clang-tidy diff --git a/Makefile b/Makefile index 65850dd..1618561 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,9 @@ python-install-development: python-install-editable: pip3 install -e .[development] +clang-tidy: + clang-tidy $(shell find ./src/cpp/ -name '*.hpp' -o -name '*.cpp') -- -I$(shell python3 -c "import sysconfig; print(sysconfig.get_path('include'))") -I$(shell python3 -c "import numpy; print(numpy.get_include())") + mypy: mypy ./src/python/ diff --git a/src/cpp/fast/foo.cpp b/src/cpp/fast/foo.cpp index dd933e6..0d7b485 100644 --- a/src/cpp/fast/foo.cpp +++ b/src/cpp/fast/foo.cpp @@ -90,4 +90,4 @@ PyInit_fast(void) PyObject* module_obj = PyModuleDef_Init(&numpy_module); import_array(); return module_obj; -} +} \ No newline at end of file From 3c1e841412671329367bc5011fd2a5591a2a31ec Mon Sep 17 00:00:00 2001 From: Dominik Breksa Date: Sun, 14 Dec 2025 19:28:06 +0100 Subject: [PATCH 5/6] feat: added README.md status badge --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4940244..442139f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # CPython-based Extension for Image Manipulation +[![CPPLinters](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/cpp_linters.yaml/badge.svg)](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/cpp_linters.yaml) +[![Linters](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/linters.yaml/badge.svg)](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/linters.yaml) + * [CPython-based Extension for Image Manipulation](#cpython-based-extension-for-image-manipulation) * [Team members](#team-members) From 7f3bf9a80e539231d018b868ae49acaf71d14bfe Mon Sep 17 00:00:00 2001 From: Dominik Breksa Date: Sun, 14 Dec 2025 19:30:55 +0100 Subject: [PATCH 6/6] fix: file organization --- .../{cpp_linters.yaml => cpp_linter.yaml} | 52 +++++++-------- .../{linters.yaml => python_linter.yaml} | 64 +++++++++---------- README.md | 4 +- 3 files changed, 60 insertions(+), 60 deletions(-) rename .github/workflows/{cpp_linters.yaml => cpp_linter.yaml} (88%) rename .github/workflows/{linters.yaml => python_linter.yaml} (90%) diff --git a/.github/workflows/cpp_linters.yaml b/.github/workflows/cpp_linter.yaml similarity index 88% rename from .github/workflows/cpp_linters.yaml rename to .github/workflows/cpp_linter.yaml index 7bb97fd..3286734 100644 --- a/.github/workflows/cpp_linters.yaml +++ b/.github/workflows/cpp_linter.yaml @@ -1,26 +1,26 @@ -name: CPPLinters - -on: - push: - branches: - - '**' - pull_request: - branches: - - '**' - -jobs: - cpplinter: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Python Setup - uses: actions/setup-python@v3 - with: - python-version: 3.13 - - - name: Install libraries - run: make python-install-development - - - name: clang-tidy - run: make clang-tidy +name: C++ Linters + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + +jobs: + cpp_linter: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Python Setup + uses: actions/setup-python@v3 + with: + python-version: 3.13 + + - name: Install libraries + run: make python-install-development + + - name: clang-tidy + run: make clang-tidy diff --git a/.github/workflows/linters.yaml b/.github/workflows/python_linter.yaml similarity index 90% rename from .github/workflows/linters.yaml rename to .github/workflows/python_linter.yaml index e696377..ecc7912 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/python_linter.yaml @@ -1,32 +1,32 @@ -name: Linters - -on: - push: - branches: - - '**' - pull_request: - branches: - - '**' - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Python Setup - uses: actions/setup-python@v3 - with: - python-version: 3.13 - - - name: Install libraries - run: make python-install-development - - - name: mypy - run: make mypy - - - name: ruff - run: make ruff - - - name: flake8 - run: make flake8 +name: Python Linters + +on: + push: + branches: + - '**' + pull_request: + branches: + - '**' + +jobs: + python_linter: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Python Setup + uses: actions/setup-python@v3 + with: + python-version: 3.13 + + - name: Install libraries + run: make python-install-development + + - name: mypy + run: make mypy + + - name: ruff + run: make ruff + + - name: flake8 + run: make flake8 diff --git a/README.md b/README.md index 442139f..e92b936 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # CPython-based Extension for Image Manipulation -[![CPPLinters](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/cpp_linters.yaml/badge.svg)](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/cpp_linters.yaml) -[![Linters](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/linters.yaml/badge.svg)](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/linters.yaml) +[![C++ Linters](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/cpp_linter.yaml/badge.svg)](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/cpp_linter.yaml) +[![Python Linters](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/python_linter.yaml/badge.svg)](https://github.com/ForNeus57/advanced-python-programming-project/actions/workflows/python_linter.yaml) * [CPython-based Extension for Image Manipulation](#cpython-based-extension-for-image-manipulation)