Skip to content

Commit

Permalink
new ruff rules
Browse files Browse the repository at this point in the history
  • Loading branch information
zeptofine committed Dec 1, 2023
1 parent 2f21e0d commit 23fea9c
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 82 deletions.
22 changes: 11 additions & 11 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 36 additions & 32 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ authors = [
{name = "zeptofine", email = "[email protected]"},
]
dependencies = [
"ImageHash<5.0.0,>=4.3.1",
"Pillow<11.0.0,>=10.0.1",
"PySide6-Essentials<7.0.0,>=6.5.2",
"ffmpeg-python<1.0.0,>=0.2.0",
"imagesize<2.0.0,>=1.4.1",
"numpy<2.0.0,>=1.26.0",
"opencv-python<5.0.0.0,>=4.8.1.78",
"pathvalidate<4.0.0,>=3.2.0",
"polars<1.0.0,>=0.19.3",
"pyarrow<14.0.0,>=13.0.0",
"python-dateutil<3.0.0,>=2.8.2",
"rich<14.0.0,>=13.5.3",
"typer<1.0.0,>=0.9.0",
"wcmatch<9.0,>=8.5",
"ImageHash<5.0.0,>=4.3.1",
"Pillow<11.0.0,>=10.0.1",
"PySide6-Essentials<7.0.0,>=6.5.2",
"ffmpeg-python<1.0.0,>=0.2.0",
"imagesize<2.0.0,>=1.4.1",
"numpy<2.0.0,>=1.26.0",
"opencv-python<5.0.0.0,>=4.8.1.78",
"pathvalidate<4.0.0,>=3.2.0",
"polars<1.0.0,>=0.19.3",
"pyarrow<14.0.0,>=13.0.0",
"python-dateutil<3.0.0,>=2.8.2",
"rich<14.0.0,>=13.5.3",
"typer<1.0.0,>=0.9.0",
"wcmatch<9.0,>=8.5",
]
description = ""
license = {text = "GPL"}
Expand All @@ -38,29 +38,33 @@ build-backend = "pdm.backend"
requires = ["pdm-backend"]

[tool.ruff]
extend-ignore = ["F401", "E501", "B905"]
extend-ignore = ["F401", "E501", "B905", "A003", "DTZ006", "DTZ005"]
extend-select = [
"A",
"ASYNC",
"UP",
"I",
"B",
"ICN",
"F",
"RET",
"SIM",
"NPY",
"PERF",
"RUF",
"PIE",
"C4",
"E", # pycodestyle
"A", # flake8-builtins
"ASYNC", # flake8-async
"UP", # pyupgrade
"I", # isort
"B", # flake8-bugbear
"ICN", # flake8-import-conventions
"F", # pyflakes
"RET", # flake8-return
"SIM", # flake8-simplify
"NPY", # NumPy-specific rules
"PERF", # perflint
"RUF", # Ruff-specific rules
"PIE", # flake8-pie
"DTZ", # flake8-datetimez
"C4", # flake8-comprehensions
"E", # Error
"EXE", # flake8-executable
"TCH", # flake8-type-checking
"W", # pycodestyle
"FA", # flake8-future-annotations
"ISC", # flake8-implicit-str-concat
"G", # flake8-logging-format
"Q", # flake8-quotes
"SLF", # flake8-self
"SLF", # flake8-self #Specific pylint rules # "PL", # Pylint
"PLR1711", # useless-return
"PLR1714", # repeated-equality-comparison
]
fixable = ["ALL"]
line-length = 120
Expand Down
2 changes: 1 addition & 1 deletion src/imdataset_creator/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import logging
from datetime import datetime
from datetime import UTC, datetime
from multiprocessing import Pool, cpu_count, freeze_support
from pathlib import Path
from random import sample
Expand Down
25 changes: 7 additions & 18 deletions src/imdataset_creator/config_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@
class ConfigHandler:
def __init__(self, cfg: MainConfig):
# generate `Input`s
self.inputs: list[Input] = [Input.from_cfg(folder["data"]) for folder in cfg["inputs"]]
self.inputs = [Input.from_cfg(folder["data"]) for folder in cfg["inputs"]]
# generate `Producer`s
self.producers: list[Producer] = [
Producer.all_producers[p["name"]].from_cfg(p["data"]) for p in cfg["producers"]
]
self.producers = [Producer.all_producers[p["name"]].from_cfg(p["data"]) for p in cfg["producers"]]

# generate `Rule`s
self.rules: list[Rule] = [Rule.all_rules[r["name"]].from_cfg(r["data"]) for r in cfg["rules"]]
self.rules = [Rule.all_rules[r["name"]].from_cfg(r["data"]) for r in cfg["rules"]]

# generate test kwargs
tkwargs = {}
Expand All @@ -29,7 +27,7 @@ def __init__(self, cfg: MainConfig):
tkwargs[name] = production.template

# generate `Output`s
self.outputs: list[Output] = [Output.from_cfg(folder["data"], tkwargs) for folder in cfg["output"]]
self.outputs = [Output.from_cfg(folder["data"], tkwargs) for folder in cfg["output"]]

@overload
def gather_images(self, sort=True, reverse=False) -> Generator[tuple[Path, list[Path]], None, None]:
Expand All @@ -39,20 +37,13 @@ def gather_images(self, sort=True, reverse=False) -> Generator[tuple[Path, list[
def gather_images(self, sort=False, reverse=False) -> Generator[tuple[Path, PathGenerator], None, None]:
...

def gather_images(
self, sort=False, reverse=False
) -> Generator[tuple[Path, PathGenerator | list[Path]], None, None]:
def gather_images(self, sort=False, reverse=False):
for input_ in self.inputs:
gen = input_.run()
if sort:
yield (
input_.folder,
list(
map(
Path,
sorted(map(str, gen), key=alphanumeric_sort, reverse=reverse),
)
),
list(map(Path, sorted(map(str, gen), key=alphanumeric_sort, reverse=reverse))),
)
else:
yield input_.folder, gen
Expand All @@ -71,7 +62,5 @@ def parse_files(self, files: Iterable[File]) -> Generator[FileScenario, None, No
return (FileScenario(file, out_s) for file in files if (out_s := self.get_outputs(file)))

def __repr__(self) -> str:
attrlist: list[str] = [
f"{key}={val!r}" for key, val in vars(self).items() if all(k not in key for k in ("__",))
]
attrlist = [f"{key}={val!r}" for key, val in vars(self).items() if all(k not in key for k in ("__",))]
return f"{self.__class__.__name__}({', '.join(attrlist)})"
12 changes: 8 additions & 4 deletions src/imdataset_creator/datarules/base_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@
from collections.abc import Callable, Generator, Iterable
from dataclasses import dataclass
from pathlib import Path
from types import MappingProxyType
from typing import Any, ClassVar
from typing import TYPE_CHECKING, Any, ClassVar

import numpy as np
import wcmatch.glob as wglob
from pathvalidate import validate_filepath
from polars import DataFrame, DataType, Expr, PolarsDataType

from ..configs import Keyworded
from ..configs.configtypes import InputData, OutputData
from ..file import File, SafeFormatter

if TYPE_CHECKING:
from types import MappingProxyType

import numpy as np

from ..configs.configtypes import InputData, OutputData

PartialDataFrame = DataFrame
FullDataFrame = DataFrame
DataTypeSchema = dict[str, DataType | type]
Expand Down
2 changes: 1 addition & 1 deletion src/imdataset_creator/datarules/dataset_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def get_unfinished(self) -> LazyFrame:
def get_unfinished_existing(self) -> LazyFrame:
return self.get_unfinished().filter(pl.col("path").apply(os.path.exists))

def filter(self, lst: Collection[str]) -> DataFrame: # noqa: A003
def filter(self, lst: Collection[str]) -> DataFrame:
if len(self.unready_rules):
warnings.warn(
f"{len(self.unready_rules)} filters are not initialized and will not be populated",
Expand Down
14 changes: 12 additions & 2 deletions src/imdataset_creator/datarules/image_rules.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from __future__ import annotations

import os
from collections.abc import Callable
from enum import Enum, StrEnum
from functools import cache
from types import MappingProxyType
from typing import Literal, Self
from typing import TYPE_CHECKING, Literal, Self

import imagehash
import polars as pl
Expand All @@ -24,6 +23,11 @@
combine_expr_conds,
)

if TYPE_CHECKING:
from collections.abc import Callable

import numpy as np


def whash_db4(img) -> imagehash.ImageHash:
return imagehash.whash(img, mode="db4")
Expand All @@ -43,6 +47,12 @@ def get_hwc(pth):
}


def get_hwc_from_np(img: np.ndarray):
h, w = img.shape[:2]
c = 1 if img.ndim == 2 else img.shape[2]
return h, w, c


class ImShapeProducer(Producer):
produces = MappingProxyType(
{
Expand Down
23 changes: 15 additions & 8 deletions src/imdataset_creator/file.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from __future__ import annotations

import re
from collections.abc import Callable, Mapping, Sequence
from dataclasses import dataclass
from pathlib import Path
from string import Formatter
from typing import Any, ClassVar
from typing import TYPE_CHECKING, Any, ClassVar

from pathvalidate import sanitize_filename
from typing_extensions import SupportsIndex

if TYPE_CHECKING:
from collections.abc import Callable, Mapping, Sequence

from typing_extensions import SupportsIndex


class InvalidFormatError(Exception):
Expand Down Expand Up @@ -41,8 +44,6 @@ def get_field(self, field_name: str, _: Sequence[Any], kwargs: Mapping[str, Any]


escaped_split = re.compile(r"(?<!\\),")
condition_fmt = re.compile(r"^(?P<prompt>[^\?:]+)\?(?P<true>(?:[^:])*):?(?P<false>.*)$") # present?yes:no
replacement_fmt = re.compile(r"'(?P<from>[^']+)'='(?P<to>[^']*)'")


def condition_format(pth: str, match: re.Match) -> str:
Expand All @@ -56,12 +57,18 @@ def condition_format(pth: str, match: re.Match) -> str:
return match.group("false")


def replacement_format(pth: str, match: re.Match) -> str:
"""
Inline replacement condition. 'from'='to'
replaces every instance of `from` to `to`.
"""
return pth.replace(match.group("from"), match.group("to"))


class MalleablePath(str):
mpath_format_conditions: ClassVar[dict[re.Pattern, Callable[[str, re.Match], str]]] = {
re.compile(r"^(?P<prompt>[^\?:]+)\?(?P<true>(?:[^:!])*):?(?P<false>.*)$"): (condition_format),
re.compile(r"^'(?P<from>[^']+)'='(?P<to>[^']*)'$"): ( # replaces <from> to <to>
lambda pth, m: pth.replace(m.group("from"), m.group("to"))
),
re.compile(r"^'(?P<from>[^']+)'='(?P<to>[^']*)'$"): (replacement_format),
}

def __format__(self, format_spec: str):
Expand Down
6 changes: 4 additions & 2 deletions src/imdataset_creator/gui/config_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import contextlib
import functools
from copy import deepcopy as objcopy
from typing import Generic, Iterable, TypeVar
from typing import TYPE_CHECKING, Generic, TypeVar

from PySide6.QtCore import QRect, Qt, Signal, Slot
from PySide6.QtGui import QAction, QMouseEvent
Expand All @@ -26,6 +26,9 @@
from ..configs.keyworded import Keyworded
from .settings_inputs import BaseInput, ItemSettings, SettingsBox, SettingsItem, apply_tooltip

if TYPE_CHECKING:
from collections.abc import Iterable

JSON_SERIALIZABLE = dict | list | tuple | str | int | float | bool | None


Expand Down Expand Up @@ -317,7 +320,6 @@ def update_menu(self):
self.add_box.setEnabled(True)
elif self.add_box.isVisible():
self.add_box.setEnabled(False)
return

def add_item_to_menu(self, item: ItemDeclaration):
self.add_menu.addAction(item.title, lambda: self.initialize_item(item))
Expand Down
2 changes: 0 additions & 2 deletions src/imdataset_creator/gui/main_window.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#!/usr/bin/python

import json
import logging
import os
Expand Down
5 changes: 4 additions & 1 deletion src/imdataset_creator/gui/minichecklist.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from __future__ import annotations

from collections.abc import Collection
from typing import TYPE_CHECKING

from PySide6.QtWidgets import (
QCheckBox,
QFrame,
QGridLayout,
)

if TYPE_CHECKING:
from collections.abc import Collection


class MiniCheckList(QFrame):
def __init__(self, items: Collection[str], *args, **kwargs):
Expand Down

0 comments on commit 23fea9c

Please sign in to comment.