diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index ed3242c..d1f5aef 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -25,14 +25,10 @@ jobs: uv venv --python ${{ matrix.python-version }} source .venv/bin/activate uv sync - - name: Lint with flake8 + - name: Lint with ruff run: | source .venv/bin/activate - - # stop the build if there are Python syntax errors or undefined names - flake8 tensorboardX --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 tensorboardX --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + ruff check tensorboardX/ - name: Test with pytest env: MPLBACKEND: Agg diff --git a/pyproject.toml b/pyproject.toml index e576371..91ada82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ dev = [ "pytest-cov>=6.0.0", "pytest>=8.3.4", "protobuf==4.22.3", - "flake8>=7.1.1", "torch>=2.5.1", "torchvision>=0.20.1", "numpy>=2.0.2", @@ -32,5 +31,32 @@ dev = [ "visdom>=0.2.4", "onnx>=1.17.0", "imageio==2.27", + "ruff>=0.8.4", ] +[tool.ruff] +# Exclude a variety of commonly ignored directories. +exclude = [ + "proto", +] + +[tool.ruff.lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade +# "UP", + # flake8-bugbear +# "B", + # flake8-simplify +# "SIM", + # isort + "I", +] +ignore = ["F401", "E501", "E721", "E741"] + diff --git a/tensorboardX/__init__.py b/tensorboardX/__init__.py index 36f75f9..5181247 100644 --- a/tensorboardX/__init__.py +++ b/tensorboardX/__init__.py @@ -1,10 +1,10 @@ """A module for visualization with tensorboard """ +from .global_writer import GlobalSummaryWriter from .record_writer import RecordWriter from .torchvis import TorchVis from .writer import FileWriter, SummaryWriter -from .global_writer import GlobalSummaryWriter try: from ._version import __version__ diff --git a/tensorboardX/comet_utils.py b/tensorboardX/comet_utils.py index 9b9edea..fcb0a89 100644 --- a/tensorboardX/comet_utils.py +++ b/tensorboardX/comet_utils.py @@ -1,10 +1,13 @@ -import logging -import json import functools +import json +import logging from io import BytesIO -from google.protobuf.json_format import MessageToJson + import numpy as np +from google.protobuf.json_format import MessageToJson + from .summary import _clean_tag + try: import comet_ml comet_installed = True diff --git a/tensorboardX/embedding.py b/tensorboardX/embedding.py index ed32a03..18acb09 100644 --- a/tensorboardX/embedding.py +++ b/tensorboardX/embedding.py @@ -58,10 +58,12 @@ def make_tsv(metadata, save_path, metadata_header=None): # https://github.com/tensorflow/tensorboard/issues/44 image label will be squared def make_sprite(label_img, save_path): import math + import numpy as np - from .x2num import make_np - from .utils import make_grid from PIL import Image + + from .utils import make_grid + from .x2num import make_np # this ensures the sprite image has correct dimension as described in # https://www.tensorflow.org/get_started/embedding_viz # There are some constraints for the sprite image: diff --git a/tensorboardX/event_file_writer.py b/tensorboardX/event_file_writer.py index 9d08aa1..b57156b 100644 --- a/tensorboardX/event_file_writer.py +++ b/tensorboardX/event_file_writer.py @@ -14,16 +14,14 @@ # ============================================================================== """Writes events to disk in a logdir.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function +from __future__ import absolute_import, division, print_function +import multiprocessing import os +import queue import socket import threading import time -import multiprocessing -import queue from .proto import event_pb2 from .record_writer import RecordWriter, directory_check diff --git a/tensorboardX/global_writer.py b/tensorboardX/global_writer.py index 68adee1..da293fa 100644 --- a/tensorboardX/global_writer.py +++ b/tensorboardX/global_writer.py @@ -1,6 +1,7 @@ -from .writer import SummaryWriter -from multiprocessing import Value import multiprocessing as mp +from multiprocessing import Value + +from .writer import SummaryWriter global _writer _writer = None diff --git a/tensorboardX/onnx_graph.py b/tensorboardX/onnx_graph.py index 90eb031..487450b 100644 --- a/tensorboardX/onnx_graph.py +++ b/tensorboardX/onnx_graph.py @@ -1,8 +1,8 @@ +from .proto.attr_value_pb2 import AttrValue from .proto.graph_pb2 import GraphDef from .proto.node_def_pb2 import NodeDef -from .proto.versions_pb2 import VersionDef -from .proto.attr_value_pb2 import AttrValue from .proto.tensor_shape_pb2 import TensorShapeProto +from .proto.versions_pb2 import VersionDef def load_onnx_graph(fname): diff --git a/tensorboardX/openvino_graph.py b/tensorboardX/openvino_graph.py index 7c089c5..2af1996 100644 --- a/tensorboardX/openvino_graph.py +++ b/tensorboardX/openvino_graph.py @@ -1,8 +1,8 @@ +from .proto.attr_value_pb2 import AttrValue from .proto.graph_pb2 import GraphDef from .proto.node_def_pb2 import NodeDef -from .proto.versions_pb2 import VersionDef -from .proto.attr_value_pb2 import AttrValue from .proto.tensor_shape_pb2 import TensorShapeProto +from .proto.versions_pb2 import VersionDef def load_openvino_graph(fname): diff --git a/tensorboardX/record_writer.py b/tensorboardX/record_writer.py index 250a7a3..f9d571e 100644 --- a/tensorboardX/record_writer.py +++ b/tensorboardX/record_writer.py @@ -3,12 +3,13 @@ The code was borrowed from https://github.com/TeamHG-Memex/tensorboard_logger """ -import os import copy import io +import os import os.path import re import struct + try: import boto3 S3_ENABLED = True @@ -22,7 +23,6 @@ from .crc32c import crc32c - _VALID_OP_NAME_START = re.compile('^[A-Za-z0-9.]') _VALID_OP_NAME_PART = re.compile('[A-Za-z0-9_.\\-/]+') diff --git a/tensorboardX/summary.py b/tensorboardX/summary.py index cbdd6a7..997bff2 100644 --- a/tensorboardX/summary.py +++ b/tensorboardX/summary.py @@ -1,25 +1,23 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function +from __future__ import absolute_import, division, print_function import logging -import numpy as np import os import re as _re -# pylint: disable=unused-import +import numpy as np -from .proto.summary_pb2 import Summary -from .proto.summary_pb2 import HistogramProto -from .proto.summary_pb2 import SummaryMetadata -from .proto.tensor_pb2 import TensorProto -from .proto.tensor_shape_pb2 import TensorShapeProto +from .proto import layout_pb2 +from .proto.plugin_mesh_pb2 import MeshPluginData from .proto.plugin_pr_curve_pb2 import PrCurvePluginData from .proto.plugin_text_pb2 import TextPluginData -from .proto.plugin_mesh_pb2 import MeshPluginData -from .proto import layout_pb2 -from .x2num import make_np + +# pylint: disable=unused-import +from .proto.summary_pb2 import HistogramProto, Summary, SummaryMetadata +from .proto.tensor_pb2 import TensorProto +from .proto.tensor_shape_pb2 import TensorShapeProto from .utils import _prepare_video, convert_to_HWC, convert_to_NTCHW +from .x2num import make_np + logger = logging.getLogger(__name__) _INVALID_TAG_CHARACTERS = _re.compile(r'[^-/\w\.]') @@ -68,8 +66,19 @@ def _draw_single_box(image, xmin, ymin, xmax, ymax, display_str, color='black', def hparams(hparam_dict=None, metric_dict=None): - from tensorboardX.proto.plugin_hparams_pb2 import HParamsPluginData, SessionEndInfo, SessionStartInfo - from tensorboardX.proto.api_pb2 import Experiment, HParamInfo, MetricInfo, MetricName, Status, DataType + from tensorboardX.proto.api_pb2 import ( + DataType, + Experiment, + HParamInfo, + MetricInfo, + MetricName, + Status, + ) + from tensorboardX.proto.plugin_hparams_pb2 import ( + HParamsPluginData, + SessionEndInfo, + SessionStartInfo, + ) PLUGIN_NAME = 'hparams' PLUGIN_DATA_VERSION = 0 @@ -322,8 +331,8 @@ def draw_boxes(disp_image, boxes, labels=None): def make_image(tensor, rescale=1, rois=None, labels=None): """Convert an numpy representation image to Image protobuf""" import PIL - from PIL import Image from packaging.version import parse + from PIL import Image height, width, channel = tensor.shape scaled_height = int(height * rescale) scaled_width = int(width * rescale) @@ -372,9 +381,10 @@ def make_video(tensor, fps): "Some packages could be missing [imageio, requests]") return - import moviepy.version import tempfile + import moviepy.version + t, h, w, c = tensor.shape # encode sequence of images into gif string @@ -410,6 +420,7 @@ def audio(tag, tensor, sample_rate=44100): The values should between [-1, 1]. We also accepts 1-D tensor. """ import io + import soundfile tensor = make_np(tensor) if abs(tensor).max() > 1: @@ -435,9 +446,7 @@ def audio(tag, tensor, sample_rate=44100): def custom_scalars(layout): - categoriesnames = layout.keys() categories = [] - layouts = [] for k, v in layout.items(): charts = [] for chart_name, chart_meatadata in v.items(): diff --git a/tensorboardX/torchvis.py b/tensorboardX/torchvis.py index 29a0e17..e012b0b 100644 --- a/tensorboardX/torchvis.py +++ b/tensorboardX/torchvis.py @@ -1,15 +1,11 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals +from __future__ import absolute_import, division, print_function, unicode_literals import gc import time - from functools import wraps -from .writer import SummaryWriter -from .visdom_writer import VisdomWriter +from .visdom_writer import VisdomWriter +from .writer import SummaryWriter # Supports both TensorBoard and Visdom (no embedding or graph visualization with Visdom) vis_formats = {'tensorboard': SummaryWriter, 'visdom': VisdomWriter} diff --git a/tensorboardX/utils.py b/tensorboardX/utils.py index 6b1a151..b1d7e19 100644 --- a/tensorboardX/utils.py +++ b/tensorboardX/utils.py @@ -13,8 +13,8 @@ def figure_to_image(figures, close=True): """ import numpy as np try: - import matplotlib.pyplot as plt import matplotlib.backends.backend_agg as plt_backend_agg + import matplotlib.pyplot as plt except ModuleNotFoundError: print('please install matplotlib') diff --git a/tensorboardX/visdom_writer.py b/tensorboardX/visdom_writer.py index ef5caa0..68a466a 100644 --- a/tensorboardX/visdom_writer.py +++ b/tensorboardX/visdom_writer.py @@ -1,9 +1,10 @@ import gc -import numpy as np -import math import json +import math import time +import numpy as np + from .summary import compute_curve from .utils import figure_to_image from .x2num import make_np diff --git a/tensorboardX/writer.py b/tensorboardX/writer.py index a6cc7f4..1f74da5 100644 --- a/tensorboardX/writer.py +++ b/tensorboardX/writer.py @@ -1,31 +1,41 @@ """Provides an API for writing protocol buffers to event files to be consumed by TensorBoard for visualization.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function +from __future__ import absolute_import, division, print_function +import atexit import json +import logging import os -import numpy import time -import logging -import atexit -from typing import Union, Optional, Dict, List +from typing import Dict, List, Optional, Union + +import numpy from .comet_utils import CometLogger -from .embedding import make_mat, make_sprite, make_tsv, append_pbtxt +from .embedding import append_pbtxt, make_mat, make_sprite, make_tsv from .event_file_writer import EventFileWriter from .onnx_graph import load_onnx_graph from .openvino_graph import load_openvino_graph -from .proto import event_pb2 -from .proto import summary_pb2 -from .proto.event_pb2 import SessionLog, Event -from .utils import figure_to_image +from .proto import event_pb2, summary_pb2 +from .proto.event_pb2 import Event, SessionLog from .summary import ( - scalar, histogram, histogram_raw, image, audio, text, - pr_curve, pr_curve_raw, video, custom_scalars, image_boxes, mesh, hparams + audio, + custom_scalars, + histogram, + histogram_raw, + hparams, + image, + image_boxes, + mesh, + pr_curve, + pr_curve_raw, + scalar, + text, + video, ) +from .utils import figure_to_image + logger = logging.getLogger(__name__) numpy_compatible = numpy.ndarray @@ -712,7 +722,7 @@ def add_images( import torch try: img_tensor = torch.stack(img_tensor, 0) - except TypeError as e: + except TypeError: import numpy as np img_tensor = np.stack(img_tensor, 0) diff --git a/tensorboardX/x2num.py b/tensorboardX/x2num.py index 2b545b5..08adc47 100644 --- a/tensorboardX/x2num.py +++ b/tensorboardX/x2num.py @@ -1,10 +1,10 @@ # DO NOT alter/distruct/free input object ! -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function +from __future__ import absolute_import, division, print_function import logging + import numpy as np + logger = logging.getLogger(__name__) diff --git a/tests/test_lint.py b/tests/test_lint.py index 5aef217..613d233 100644 --- a/tests/test_lint.py +++ b/tests/test_lint.py @@ -1,3 +1,3 @@ def test_linting(): import subprocess - subprocess.check_output(['flake8', 'tensorboardX']) + subprocess.check_output(['ruff', 'check', 'tensorboardX'])