diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a0945cf..76b160a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,6 @@ jobs: - name: Install Pango run: sudo apt-get update && sudo apt-get install libpango1.0-dev - name: Install Dependencies - run: uv sync --extra torch --extra torch-common --extra vision + run: uv sync --extra torch --extra torch-extras --extra vision - name: Test run: uv run pytest diff --git a/.github/workflows/verify-py.yml b/.github/workflows/verify-py.yml index b26a4c0..a79bf37 100644 --- a/.github/workflows/verify-py.yml +++ b/.github/workflows/verify-py.yml @@ -4,6 +4,7 @@ on: jobs: format-py: name: Format Python + if: false runs-on: ubuntu-latest steps: - name: Checkout diff --git a/camp/datasets/ikcest.py b/camp/datasets/ikcest.py index 29f77a2..63a5f9a 100644 --- a/camp/datasets/ikcest.py +++ b/camp/datasets/ikcest.py @@ -151,7 +151,7 @@ class IKCESTDetectionDataset(Dataset): def __init__( self, path: str, - subset: str, # noqa: ARG002 + _subset: str, storage_options: dict | None = None, transforms: Callable | None = None, ) -> None: diff --git a/camp/datasets/mnist.py b/camp/datasets/mnist.py index 8b83ce3..312b6a3 100644 --- a/camp/datasets/mnist.py +++ b/camp/datasets/mnist.py @@ -33,13 +33,13 @@ def load( mnist = FashionMNIST() buffers = mnist._load(path, storage_options) - arrays = mnist._parse(buffers) + arrays = _parse(buffers) if return_tensors == "np": return arrays if return_tensors == "pt": - return mnist._to_tensor(arrays) + return _to_tensor(arrays) return None @@ -52,37 +52,36 @@ def _load(self, path: str, storage_options: dict) -> dict[str, bytes]: return buffers - def _parse(self, buffers: dict[str, bytes]) -> dict[str, np.ndarray]: - arrays = {} - for subset in ["train", "test"]: - header = struct.unpack(">IIII", buffers[subset][0:16]) - _magic_number, n_items, n_rows, n_cols = header +def _parse(buffers: dict[str, bytes]) -> dict[str, np.ndarray]: + arrays = {} - images = np.frombuffer(buffers[subset][16:], dtype=np.uint8) - images = images.reshape(n_items, n_rows * n_cols) + for subset in ["train", "test"]: + header = struct.unpack(">IIII", buffers[subset][0:16]) + _magic_number, n_items, n_rows, n_cols = header - arrays[subset] = images + images = np.frombuffer(buffers[subset][16:], dtype=np.uint8) + images = images.reshape(n_items, n_rows * n_cols) - for subset in ["train_labels", "test_labels"]: - _magic_number, n_items = struct.unpack(">II", buffers[subset][0:8]) - labels = np.frombuffer(buffers[subset][8:], dtype=np.uint8) + arrays[subset] = images - arrays[subset] = labels + for subset in ["train_labels", "test_labels"]: + _magic_number, n_items = struct.unpack(">II", buffers[subset][0:8]) + labels = np.frombuffer(buffers[subset][8:], dtype=np.uint8) - return arrays + arrays[subset] = labels - def _to_tensor( - self, - arrays: dict[str, np.ndarray], - ) -> dict[str, torch.Tensor] | None: - if torch is None: - print("cannot convert to tensors because torch is not installed.") - return None + return arrays - tensors = {} - for k, v in arrays.items(): - tensors[k] = torch.from_numpy(v) +def _to_tensor(arrays: dict[str, np.ndarray]) -> dict[str, torch.Tensor] | None: + if torch is None: + print("cannot convert to tensors because torch is not installed.") + return None + + tensors = {} + + for k, v in arrays.items(): + tensors[k] = torch.from_numpy(v) - return tensors + return tensors diff --git a/camp/datasets/soccernet.py b/camp/datasets/soccernet.py index b9255fd..2fdbeca 100644 --- a/camp/datasets/soccernet.py +++ b/camp/datasets/soccernet.py @@ -54,7 +54,7 @@ def read_json(f: str) -> dict: elif protocol == "file": def read_json(filename: str) -> dict: - with Path(filename).open("r") as f: + with Path(filename).open("r", encoding="utf-8") as f: return json.load(f) return list(pool.map(read_json, files)) @@ -177,7 +177,7 @@ def __init__( self.storage_options = storage_options self.transforms = transforms - def _transform_subset(self, subset: str) -> str: + def _transform_subset(self, subset: str) -> str: # noqa: PLR6301 mapping = {"val": "valid"} return mapping.get(subset, subset) diff --git a/camp/utils/jupyter_utils.py b/camp/utils/jupyter_utils.py index d542741..f4e7da8 100644 --- a/camp/utils/jupyter_utils.py +++ b/camp/utils/jupyter_utils.py @@ -7,7 +7,7 @@ def is_notebook() -> bool: class StopExecutionError(Exception): - def _render_traceback_(self) -> None: + def _render_traceback_(self) -> None: # noqa: PLW3201 pass diff --git a/examples/grafana/smartctl/apply.py b/examples/grafana/smartctl/apply.py index 49e6a37..bf1a285 100644 --- a/examples/grafana/smartctl/apply.py +++ b/examples/grafana/smartctl/apply.py @@ -8,7 +8,7 @@ json = JSONEncoder(sort_keys=True, indent=2).encode(manifest()) -with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmp: +with tempfile.NamedTemporaryFile(encoding="utf-8", mode="w", suffix=".json", delete=False) as tmp: tmp.write(json) cmd = ["grafanactl", "resources", "push", "dashboards", "--path", tmp.name] diff --git a/examples/http/_bench/utils.py b/examples/http/_bench/utils.py index 2cc4b7c..d772fad 100644 --- a/examples/http/_bench/utils.py +++ b/examples/http/_bench/utils.py @@ -167,7 +167,7 @@ def save_result(result: BenchmarkResult, results_file: Path) -> None: "mean_latency_us": result.mean_latency_us, } - with results_file.open("a") as f: + with results_file.open("a", encoding="utf-8") as f: f.write(json.dumps(data) + "\n") diff --git a/notebooks/random/color_models.py b/notebooks/random/color_models.py index 0389f48..a0511aa 100644 --- a/notebooks/random/color_models.py +++ b/notebooks/random/color_models.py @@ -7,7 +7,7 @@ def rgb_to_cmy(pixel: list | tuple, normalize: bool = False) -> tuple: pixel_np = np.array(pixel) if normalize: - pixel_np = pixel_np / 255 + pixel_np = pixel_np / 255 # noqa: PLR6104 return tuple(1 - pixel_np) diff --git a/notebooks/reinforcement_learning/frozen_lake.py b/notebooks/reinforcement_learning/frozen_lake.py index 9be20fd..c2992a5 100644 --- a/notebooks/reinforcement_learning/frozen_lake.py +++ b/notebooks/reinforcement_learning/frozen_lake.py @@ -126,7 +126,7 @@ def compute_q_value( _, next_state, reward, _ = env.unwrapped.P[state][action][0] - if next_state == state or next_state in [5, 7, 11, 12]: + if next_state == state or next_state in {5, 7, 11, 12}: reward = -1 return reward + gamma * V[next_state] @@ -149,7 +149,7 @@ def improve_policy( improved_policy = {} for state in range(n_states): - max_action = max(range(n_actions), key=lambda action: Q[(state, action)]) + max_action = max(range(n_actions), key=lambda action: Q[state, action]) improved_policy[state] = max_action return improved_policy, Q diff --git a/notebooks/reinforcement_learning/lunar_lander.py b/notebooks/reinforcement_learning/lunar_lander.py index 7265b61..1a28737 100644 --- a/notebooks/reinforcement_learning/lunar_lander.py +++ b/notebooks/reinforcement_learning/lunar_lander.py @@ -31,7 +31,7 @@ # %% class ReplayBuffer: def __init__(self, capacity: int) -> None: - self.buffer = deque([], maxlen=capacity) + self.buffer = deque(maxlen=capacity) def __len__(self) -> int: return len(self.buffer) diff --git a/notebooks/text/ngram_language_models.py b/notebooks/text/ngram_language_models.py index d6b1d4c..725e857 100644 --- a/notebooks/text/ngram_language_models.py +++ b/notebooks/text/ngram_language_models.py @@ -228,7 +228,7 @@ # %% def generate(text_seed: list[str], random_seed: int) -> str: - sentence = text_seed[:] + sentence = text_seed.copy() random_seed = random.Random(random_seed) # noqa: S311 while True: diff --git a/notebooks/vision/fashion_mnist.py b/notebooks/vision/fashion_mnist.py index b02b0d0..c5e7337 100644 --- a/notebooks/vision/fashion_mnist.py +++ b/notebooks/vision/fashion_mnist.py @@ -102,7 +102,7 @@ loss.backward() optimizer.step() - steps += 1 + steps += 1 # noqa: SIM113 # %% metrics = MetricCollection( diff --git a/notebooks/vision/faster_rcnn.py b/notebooks/vision/faster_rcnn.py index 0e3a68c..3643da0 100644 --- a/notebooks/vision/faster_rcnn.py +++ b/notebooks/vision/faster_rcnn.py @@ -160,7 +160,7 @@ def collate_fn(batch: list) -> tuple: losses.backward() optimizer.step() - steps += 1 + steps += 1 # noqa: SIM113 lr_scheduler.step() epochs += 1 @@ -171,11 +171,12 @@ def collate_fn(batch: list) -> tuple: save_optimizer(checkpoint_path, optimizer) -with Path(f"{checkpoint_path}/scheduler.json").open("w") as f: - f.write(json.dumps(lr_scheduler.state_dict())) +Path(f"{checkpoint_path}/scheduler.json").write_text( + json.dumps(lr_scheduler.state_dict()), + encoding="utf-8", +) -with Path(f"{checkpoint_path}/model.safetensors").open("wb") as f: - f.write(save(model.state_dict())) +Path(f"{checkpoint_path}/model.safetensors").write_bytes(save(model.state_dict())) # %% epochs = 20 @@ -183,11 +184,10 @@ def collate_fn(batch: list) -> tuple: load_optimizer(checkpoint_path, optimizer) -with Path(f"{checkpoint_path}/scheduler.json").open("r") as f: - lr_scheduler.load_state_dict(json.loads(f.read())) +scheduler_json = Path(f"{checkpoint_path}/scheduler.json").read_text(encoding="utf-8") +lr_scheduler.load_state_dict(json.loads(scheduler_json)) -with Path(f"{checkpoint_path}/model.safetensors").open("rb") as f: - model.load_state_dict(load(f.read())) +model.load_state_dict(load(Path(f"{checkpoint_path}/model.safetensors").read_bytes())) # %% # %%time diff --git a/packages/config/lint-staged.js b/packages/config/lint-staged.js index 8bf0328..6e98f44 100644 --- a/packages/config/lint-staged.js +++ b/packages/config/lint-staged.js @@ -15,7 +15,7 @@ export default { '*.py': [ 'uv run ruff check', 'uv run ruff check --select I', - 'uv run ruff format --check', - 'uv run mypy', + // 'uv run ruff format --check', + // 'uv run mypy', ], }; diff --git a/packages/config/package.json b/packages/config/package.json index b3b8287..bf376d2 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -11,7 +11,7 @@ "eslint": "9.39.2", "eslint-config-flat-gitignore": "2.1.0", "eslint-import-resolver-typescript": "4.4.4", - "eslint-plugin-better-tailwindcss": "4.1.1", + "eslint-plugin-better-tailwindcss": "4.2.0", "eslint-plugin-compat": "npm:@cmpx/eslint-plugin-compat@6.0.3", "eslint-plugin-import-x": "4.16.1", "eslint-plugin-jsx-a11y": "6.10.2", @@ -19,10 +19,10 @@ "eslint-plugin-react": "7.37.5", "eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-react-you-might-not-need-an-effect": "0.8.5", - "eslint-plugin-unicorn": "62.0.0", + "eslint-plugin-unicorn": "63.0.0", "globals": "17.3.0", "lint-staged": "16.2.7", - "oxlint": "1.43.0", + "oxlint": "1.47.0", "postcss-scss": "4.0.9", "postcss-styled-syntax": "0.7.1", "prettier": "3.8.1", diff --git a/packages/config/ruff.toml b/packages/config/ruff.toml index 6553147..8be9674 100644 --- a/packages/config/ruff.toml +++ b/packages/config/ruff.toml @@ -4,7 +4,69 @@ indent-width = 2 line-ending = "lf" [lint] -select = ["ALL"] +preview = true +select = [ + "AIR", + # "ERA", # commented-out-code + "FAST", + "YTT", + "ANN", + "ASYNC", + "S", + "BLE", + "FBT", + "B", + "A", + "COM", + "C4", + # "CPY", # missing-copyright-notice + "DTZ", + "T10", + "DJ", + "EM", + "EXE", + "FIX", + "FA", + "INT", + "ISC", + "ICN", + "LOG", + "G", + # "INP", # implicit-namespace-package + "PIE", + # "T20", # print, p-print + "PYI", + "PT", + "Q", + "RSE", + "RET", + # "SLF", # private-member-access + "SIM", + "SLOT", + "TID", + "TD", + "TC", + "ARG", + "PTH", + "FLY", + "I", + "C90", + "NPY", + "PD", + "N", + "PERF", + "E", + "W", + # "DOC", + "D", + "F", + "PGH", + "PL", + "UP", + "FURB", + "RUF", + "TRY" +] ignore = [ "D100", # undocumented-public-module "D101", # undocumented-public-class @@ -12,6 +74,8 @@ ignore = [ "D103", # undocumented-public-function "D105", # undocumented-magic-method "D107", # undocumented-public-init + "E111", # indentation-with-invalid-multiple + "E114", # indentation-with-invalid-multiple-comment "E501", # line-too-long "E731", # lambda-assignment "E741", # ambiguous-variable-name @@ -20,16 +84,17 @@ ignore = [ "N806", # non-lowercase-variable-in-function "N812", # lowercase-imported-as-non-lowercase "S101", # assert - "T201", # print - "ERA001", # commented-out-code + "S403", # suspicious-pickle-import + "S404", # suspicious-subprocess-import "FBT001", # boolean-type-hint-positional-argument "FBT002", # boolean-default-value-positional-argument - "INP001", # implicit-namespace-package - "SLF001", # private-member-access "PERF401", # manual-list-comprehension + "PLC2701", # import-private-name + "PLR0914", # too-many-locals "PLR2004", # magic-value-comparison ] allowed-confusables = [ + "µ", "σ", "∗", ] diff --git a/pyproject.toml b/pyproject.toml index 6b98060..a855dec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,30 +4,30 @@ version = "2024.0.0" requires-python = ">= 3.11" dependencies = [ "altair[all]==6.0.0", - "fsspec==2025.12.0", - "keras==3.13.0", - "manim==0.19.1", + "fsspec==2026.2.0", + "keras==3.13.2", + "manim==0.19.2", "matplotlib==3.10.8", "minio==7.2.20", - "numpy==2.4.0", + "numpy==2.4.2", "pandas==2.3.3", - "polars==1.36.1", - "psutil==7.1.3", - "pyarrow==22.0.0", - "rich[jupyter]==14.2.0", - "s3fs==2025.12.0", + "polars==1.38.1", + "psutil==7.2.2", + "pyarrow==23.0.0", + "rich[jupyter]==14.3.2", + "s3fs==2026.2.0", "scikit-learn==1.8.0", - "scipy==1.16.3", + "scipy==1.17.0", "seaborn==0.13.2", "statsmodels==0.14.6", - "streamlit==1.52.2", + "streamlit==1.54.0", "sympy==1.14.0", "tabulate==0.9.0", ] [project.optional-dependencies] distributed = [ - "pyspark==4.0.0", + "pyspark==4.1.1", ] gym = [ "gymnasium[atari,box2d,classic-control,mujoco,toy-text]==1.2.3", @@ -37,36 +37,36 @@ tensorflow = [ ] text = [ "en_core_web_sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl", - "gensim @ git+https://github.com/piskvorky/gensim@8f81545", + "gensim==4.4.0", "nltk==3.9.2", "spacy==3.8.11", ] torch = [ - "torch==2.8.0", - "torchvision==0.23.0", + "torch==2.10.0", + "torchvision==0.25.0", ] -torch-common = [ +torch-cu129 = [ + "torch==2.10.0", + "torchvision==0.25.0", +] +torch-extras = [ "deepspeed @ https://github.com/yjoer/camp/releases/download/v2025.6.0/deepspeed-0.15.0+55b4cae8-py3-none-any.whl", "safetensors==0.6.2", "torchmetrics==1.8.2", ] -torch-cu129 = [ - "torch==2.8.0", - "torchvision==0.23.0", -] tree = [ "catboost==1.2.8", "lightgbm==4.6.0", - "xgboost==3.1.2", + "xgboost==3.2.0", ] vision = [ "mmcv>=2.2.0", "mmdet>=3.3.0", "mmengine>=0.10.4", "motmetrics @ git+https://github.com/cheind/py-motmetrics@057504b", - "pillow==12.0.0", + "pillow==12.1.1", "supervision>=0.22.0", - "timm==1.0.22", + "timm==1.0.24", "ultralytics==8.3.189", ] @@ -75,21 +75,21 @@ dev = [ # "jedi-language-server==0.46.0", # "jupyterlab-lsp==5.2.0", "jjava==1.0a6", - "jupyter-collaboration==4.2.0", + "jupyter-collaboration==4.2.1", "jupyter-ruff @ git+https://github.com/leotaku/jupyter-ruff@991d3a5", - "jupyterlab==4.5.1", - "jupyterlab-git==0.51.3", + "jupyterlab==4.5.4", + "jupyterlab-git==0.51.4", "jupyterlab-quickopen @ https://github.com/yjoer/camp/releases/download/v2025.6.0/jupyterlab_quickopen-2.0.1-py3-none-any.whl", - "jupytext==1.18.1", - "jupyverse[jupyterlab,auth]==0.10.30", - "marimo==0.18.4", - "maturin==1.10.2", - "mypy==1.19.1", - "notebook-intelligence==3.1.0", + "jupytext==1.19.1", + "jupyverse[jupyterlab,auth]==0.13.3", + "marimo==0.19.11", + "maturin==1.11.5", + "notebook-intelligence==4.3.1", "pytest==9.0.2", "pytest-xdist==3.8.0", - "ruff==0.14.10", + "ruff==0.15.1", "scalene==1.5.55", + "ty==0.0.16", ] [build-system] diff --git a/solutions/sports/numbers/resnet.py b/solutions/sports/numbers/resnet.py index c2f0365..e8d3675 100644 --- a/solutions/sports/numbers/resnet.py +++ b/solutions/sports/numbers/resnet.py @@ -181,7 +181,7 @@ optimizer.zero_grad() - step += 1 + step += 1 # noqa: SIM113 if ((epoch + 1) % save_epochs) == 0: save_checkpoint( diff --git a/solutions/sports/yolo_v8.py b/solutions/sports/yolo_v8.py index b82633e..ff6926c 100644 --- a/solutions/sports/yolo_v8.py +++ b/solutions/sports/yolo_v8.py @@ -337,7 +337,7 @@ def validation_loop() -> tuple: optimizer.zero_grad() ema.update(yolo.model) - steps += 1 + steps += 1 # noqa: SIM113 train_loss = {} train_loss["cls"] = pbar._values["cls_loss"][0]