diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..607d783 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,16 @@ +name: Lint +on: [push, pull_request] +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v4 + with: + version: "latest" + - uses: actions/setup-python@v4 + with: + python-version: "3.12" + - run: uv sync --group dev + - run: uv run ruff check . + - run: uv run mypy . \ No newline at end of file diff --git a/main.py b/main.py deleted file mode 100644 index 4410167..0000000 --- a/main.py +++ /dev/null @@ -1,6 +0,0 @@ -def main(): - print("Hello from scratchgpt!") - - -if __name__ == "__main__": - main() diff --git a/pyproject.toml b/pyproject.toml index c1ebc7a..addec80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,44 +22,51 @@ dependencies = [ [dependency-groups] dev = [ "bandit>=1.8.6", - "black>=25.1.0", - "isort>=6.0.1", "mypy>=1.17.1", - "pylint>=3.3.8", "pytest>=8.4.1", + "ruff>=0.1.0", ] -[tool.isort] -profile = "black" -line_length = 120 -force_sort_within_sections = true -sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"] -default_section = "THIRDPARTY" -skip_glob = [".venv"] - -[tool.pylint."MESSAGES CONTROL"] -disable = ["missing-module-docstring", "missing-class-docstring"] -extension-pkg-whitelist = "pydantic" - -[tool.pylint.REPORTS] -output-format = "parseable" +[tool.pytest.ini_options] +asyncio_mode = "auto" -[tool.pylint.FORMAT] -max-line-length = 120 +[tool.mypy] +python_version = "3.12" +warn_unused_configs = true +files = ["scratchgpt/"] +ignore_missing_imports = false +check_untyped_defs = true +explicit_package_bases = true +warn_unreachable = true +warn_redundant_casts = true +strict = true +exclude = [".venv"] -[tool.pylint.DESIGN] -max-args = 10 -max-attributes = 10 +[[tool.mypy.overrides]] +module = ["ptflops"] +ignore_missing_imports = true -[tool.black] +[tool.ruff] line-length = 120 -target-version = ['py312'] +target-version = "py312" -[tool.pytest.ini_options] -asyncio_mode = "auto" +[tool.ruff.lint] +select = [ + "F", # Pyflakes + "E", # pycodestyle errors + "W", # pycodestyle warnings + "I", # isort + "N", # pep8-naming + "UP", # pyupgrade + "B", # flake8-bugbear (catches common bugs) + "C4", # flake8-comprehensions + "PIE", # flake8-pie + "SIM", # flake8-simplify +] +ignore = ["N812", "N806"] -[tool.mypy] -python_version = "3.12" +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] # Allow unused imports in __init__.py [build-system] requires = ["hatchling"] diff --git a/scratchgpt/dataloader.py b/scratchgpt/dataloader.py index 3be6c60..ddc6036 100644 --- a/scratchgpt/dataloader.py +++ b/scratchgpt/dataloader.py @@ -1,5 +1,4 @@ from abc import ABC, abstractmethod -import os from pathlib import Path from typing import Literal, override @@ -12,7 +11,7 @@ class TextProvider(ABC): @abstractmethod - def get_text(self) -> Path: + def get_text(self) -> str: """This method fetches the text from the underlying storage""" @@ -22,7 +21,7 @@ def __init__(self, file_path: Path) -> None: raise ValueError(f"File path {file_path} does not exist") self._data = "" - with open(file_path, "r") as f: + with open(file_path) as f: self._data = f.read() @override @@ -40,12 +39,10 @@ def __init__(self, dir_path: Path) -> None: self._data = "" for file_path in dir_path.rglob("*"): # Recursively find all files + print(f"Loading data from {file_path}") if file_path.is_file() and not file_path.name.startswith("."): - print(f"Loading data from {file_path.parent}") - with open(file_path, "r", encoding="utf-8") as f: - self._data += f.read() + "\n" # Concatenate with a - # newline between files, could be the place to add - # special tokens + with open(file_path, encoding="utf-8") as f: + self._data += f.read() + "\n" @override def get_text(self) -> str: diff --git a/scratchgpt/infer.py b/scratchgpt/infer.py index 0642193..0a47878 100644 --- a/scratchgpt/infer.py +++ b/scratchgpt/infer.py @@ -8,7 +8,7 @@ from scratchgpt.config import ScratchGPTConfig -from .main import TransformerLanguageModel +from .model.model import TransformerLanguageModel from .model_io import get_best_model_weights_path, get_tokenizer, load_model diff --git a/scratchgpt/main.py b/scratchgpt/main.py index 61c2002..b12ab2e 100644 --- a/scratchgpt/main.py +++ b/scratchgpt/main.py @@ -1,11 +1,11 @@ import argparse import os -from pathlib import Path import sys +from pathlib import Path from typing import Literal import torch -from pydantic_yaml import to_yaml_file, parse_yaml_file_as +from pydantic_yaml import parse_yaml_file_as, to_yaml_file from rich.pretty import pprint as rpprint from torch.optim.adamw import AdamW from torch.optim.optimizer import Optimizer @@ -227,4 +227,4 @@ def main() -> None: if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/scratchgpt/metering.py b/scratchgpt/metering.py index 514f92d..9fd3bdb 100644 --- a/scratchgpt/metering.py +++ b/scratchgpt/metering.py @@ -19,7 +19,7 @@ def value(self) -> tuple[float, float]: class AverageValueMeter(Meter): def __init__(self) -> None: - super(AverageValueMeter, self).__init__() + super().__init__() self.reset() self.val: float = 0.0 diff --git a/scratchgpt/model/model.py b/scratchgpt/model/model.py index 535d159..2e1f7b0 100644 --- a/scratchgpt/model/model.py +++ b/scratchgpt/model/model.py @@ -1,8 +1,8 @@ import math from typing import Any -from ptflops import get_model_complexity_info import torch +from ptflops import get_model_complexity_info from torch import Tensor, nn from torch.nn import functional as F @@ -61,7 +61,7 @@ def __init__( self._dropout = nn.Dropout(dropout_rate) def forward(self, context: Tensor) -> Tensor: - out = torch.cat([head(context) for head in self._heads], dim=-1) + out: Tensor = torch.cat([head(context) for head in self._heads], dim=-1) out = self._proj(out) out = self._dropout(out) return out @@ -202,12 +202,11 @@ def input_constructor(input_shape: Any) -> Tensor: flops, params = get_model_complexity_info( model, input_shape, - input_constructor=input_constructor, # type: ignore + input_constructor=input_constructor, print_per_layer_stat=False, as_strings=False, ) print(f" FLOPs per forward pass: {flops:,}") - print(f"GFLOPs per forward pass: {flops / 1e9:.2f}") print("=========================") diff --git a/scratchgpt/model_io.py b/scratchgpt/model_io.py index fbe69b7..9e15545 100644 --- a/scratchgpt/model_io.py +++ b/scratchgpt/model_io.py @@ -1,6 +1,6 @@ import os -from pathlib import Path import pickle +from pathlib import Path import torch @@ -10,7 +10,7 @@ from .tokenizer.tiktoken import TiktokenWrapper -class ModelLoadFailed(Exception): +class ModelLoadFailedError(Exception): pass @@ -33,8 +33,8 @@ def load_model(model_path: Path, model: TransformerLanguageModel, device: torch. print(f"Loading weights from: {model_path}") model_dict = torch.load(model_path, map_location=device) model.load_state_dict(model_dict) - except Exception: - raise ModelLoadFailed(model_path) + except Exception as error: + raise ModelLoadFailedError(model_path) from error else: print("No saved model, starting from scratch...gpt, lol!") return model diff --git a/scratchgpt/tokenizer/char_tokenizer.py b/scratchgpt/tokenizer/char_tokenizer.py index e57f5e3..b4be83f 100644 --- a/scratchgpt/tokenizer/char_tokenizer.py +++ b/scratchgpt/tokenizer/char_tokenizer.py @@ -4,7 +4,7 @@ def get_vocab(text: str) -> list[str]: - chars = sorted(list(set(text))) + chars = sorted(set(text)) return chars @@ -13,7 +13,7 @@ def str_to_int(chars: list[str]) -> dict[str, int]: def int_to_str(chars: list[str]) -> dict[int, str]: - return {idx: char for idx, char in enumerate(chars)} + return dict(enumerate(chars)) class CharTokenizer(Tokenizer): @@ -48,7 +48,7 @@ def decode( class Utf8Tokenizer(Tokenizer): def __init__(self) -> None: - self._vocabulary = list(range(0, 256)) + self._vocabulary = list(range(256)) @property @override diff --git a/scratchgpt/tokenizer/tiktoken.py b/scratchgpt/tokenizer/tiktoken.py index c5131ee..b8d3e4b 100644 --- a/scratchgpt/tokenizer/tiktoken.py +++ b/scratchgpt/tokenizer/tiktoken.py @@ -39,7 +39,7 @@ def vocabulary(self) -> list[str]: """Return the learned vocabulary""" return list(self._get_cached_vocabulary()) - @lru_cache(maxsize=1) + @lru_cache(maxsize=1) # noqa: B019 def _get_cached_vocabulary(self) -> tuple[str, ...]: """ Cache and return the vocabulary as a tuple. diff --git a/tests/test_tokenizer.py b/tests/test_tokenizer.py index 0ce3ff2..8aeba6b 100644 --- a/tests/test_tokenizer.py +++ b/tests/test_tokenizer.py @@ -1,22 +1,22 @@ from scratchgpt.tokenizer.char_tokenizer import CharTokenizer, Utf8Tokenizer - test_data = [ - "Привет, как дела? 😊", - "Я люблю читать книги.", - "Москва - это красивый город.", - "안녕하세요 👋", - "나는 당신을 만나서 행복해요 😊", - "서울은 아름다운 도시입니다.", - "Ciao, come stai? 😊", - "Amo leggere libri.", - "Roma è una città bellissima.", - "Hello, how are you? 👋", - "I love to read books.", - "New York City is a bustling metropolis 🗽️" + "Привет, как дела? 😊", + "Я люблю читать книги.", + "Москва - это красивый город.", + "안녕하세요 👋", + "나는 당신을 만나서 행복해요 😊", + "서울은 아름다운 도시입니다.", + "Ciao, come stai? 😊", + "Amo leggere libri.", + "Roma è una città bellissima.", + "Hello, how are you? 👋", + "I love to read books.", + "New York City is a bustling metropolis 🗽️", ] -def test_basic_char_tokenizer(): + +def test_basic_char_tokenizer() -> None: test_corpus = "".join(test_data) tokenizer = CharTokenizer(test_corpus) @@ -27,7 +27,7 @@ def test_basic_char_tokenizer(): assert test_sample == decoded, "Oh no, this thing failed" -def test_utf8_tokenizer(): +def test_utf8_tokenizer() -> None: tokenizer = Utf8Tokenizer() for test_sample in test_data: diff --git a/uv.lock b/uv.lock index 0d4ba7a..e73f2d5 100644 --- a/uv.lock +++ b/uv.lock @@ -11,15 +11,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] -[[package]] -name = "astroid" -version = "3.3.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/74/dfb75f9ccd592bbedb175d4a32fc643cf569d7c218508bfbd6ea7ef9c091/astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce", size = 400439, upload-time = "2025-07-13T18:04:23.177Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/0f/3b8fdc946b4d9cc8cc1e8af42c4e409468c84441b933d037e101b3d72d86/astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec", size = 275612, upload-time = "2025-07-13T18:04:21.07Z" }, -] - [[package]] name = "bandit" version = "1.8.6" @@ -35,30 +26,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/48/ca/ba5f909b40ea12ec542d5d7bdd13ee31c4d65f3beed20211ef81c18fa1f3/bandit-1.8.6-py3-none-any.whl", hash = "sha256:3348e934d736fcdb68b6aa4030487097e23a501adf3e7827b63658df464dddd0", size = 133808, upload-time = "2025-07-06T03:10:49.134Z" }, ] -[[package]] -name = "black" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449, upload-time = "2025-01-29T04:15:40.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988, upload-time = "2025-01-29T05:37:16.707Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985, upload-time = "2025-01-29T05:37:18.273Z" }, - { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816, upload-time = "2025-01-29T04:18:33.823Z" }, - { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860, upload-time = "2025-01-29T04:19:12.944Z" }, - { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673, upload-time = "2025-01-29T05:37:20.574Z" }, - { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190, upload-time = "2025-01-29T05:37:22.106Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926, upload-time = "2025-01-29T04:18:58.564Z" }, - { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613, upload-time = "2025-01-29T04:19:27.63Z" }, - { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, -] - [[package]] name = "certifi" version = "2025.8.3" @@ -110,18 +77,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, ] -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -131,15 +86,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] -[[package]] -name = "dill" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, -] - [[package]] name = "filelock" version = "3.19.1" @@ -176,15 +122,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] -[[package]] -name = "isort" -version = "6.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955, upload-time = "2025-02-26T21:13:16.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186, upload-time = "2025-02-26T21:13:14.911Z" }, -] - [[package]] name = "jinja2" version = "3.1.6" @@ -247,15 +184,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, ] -[[package]] -name = "mccabe" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, -] - [[package]] name = "mdurl" version = "0.1.2" @@ -531,15 +459,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, ] -[[package]] -name = "platformdirs" -version = "4.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, -] - [[package]] name = "pluggy" version = "1.6.0" @@ -655,24 +574,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] -[[package]] -name = "pylint" -version = "3.3.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "astroid" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "dill" }, - { name = "isort" }, - { name = "mccabe" }, - { name = "platformdirs" }, - { name = "tomlkit" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/58/1f614a84d3295c542e9f6e2c764533eea3f318f4592dc1ea06c797114767/pylint-3.3.8.tar.gz", hash = "sha256:26698de19941363037e2937d3db9ed94fb3303fdadf7d98847875345a8bb6b05", size = 1523947, upload-time = "2025-08-09T09:12:57.234Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/1a/711e93a7ab6c392e349428ea56e794a3902bb4e0284c1997cff2d7efdbc1/pylint-3.3.8-py3-none-any.whl", hash = "sha256:7ef94aa692a600e82fabdd17102b73fc226758218c97473c7ad67bd4cb905d83", size = 523153, upload-time = "2025-08-09T09:12:54.836Z" }, -] - [[package]] name = "pytest" version = "8.4.1" @@ -840,6 +741,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/85/e8e751d8791564dd333d5d9a4eab0a7a115f7e349595417fd50ecae3395c/ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3", size = 115190, upload-time = "2024-10-20T10:13:10.66Z" }, ] +[[package]] +name = "ruff" +version = "0.12.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/eb/8c073deb376e46ae767f4961390d17545e8535921d2f65101720ed8bd434/ruff-0.12.10.tar.gz", hash = "sha256:189ab65149d11ea69a2d775343adf5f49bb2426fc4780f65ee33b423ad2e47f9", size = 5310076, upload-time = "2025-08-21T18:23:22.595Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/e7/560d049d15585d6c201f9eeacd2fd130def3741323e5ccf123786e0e3c95/ruff-0.12.10-py3-none-linux_armv6l.whl", hash = "sha256:8b593cb0fb55cc8692dac7b06deb29afda78c721c7ccfed22db941201b7b8f7b", size = 11935161, upload-time = "2025-08-21T18:22:26.965Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b0/ad2464922a1113c365d12b8f80ed70fcfb39764288ac77c995156080488d/ruff-0.12.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ebb7333a45d56efc7c110a46a69a1b32365d5c5161e7244aaf3aa20ce62399c1", size = 12660884, upload-time = "2025-08-21T18:22:30.925Z" }, + { url = "https://files.pythonhosted.org/packages/d7/f1/97f509b4108d7bae16c48389f54f005b62ce86712120fd8b2d8e88a7cb49/ruff-0.12.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d59e58586829f8e4a9920788f6efba97a13d1fa320b047814e8afede381c6839", size = 11872754, upload-time = "2025-08-21T18:22:34.035Z" }, + { url = "https://files.pythonhosted.org/packages/12/ad/44f606d243f744a75adc432275217296095101f83f966842063d78eee2d3/ruff-0.12.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:822d9677b560f1fdeab69b89d1f444bf5459da4aa04e06e766cf0121771ab844", size = 12092276, upload-time = "2025-08-21T18:22:36.764Z" }, + { url = "https://files.pythonhosted.org/packages/06/1f/ed6c265e199568010197909b25c896d66e4ef2c5e1c3808caf461f6f3579/ruff-0.12.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b4a64f4062a50c75019c61c7017ff598cb444984b638511f48539d3a1c98db", size = 11734700, upload-time = "2025-08-21T18:22:39.822Z" }, + { url = "https://files.pythonhosted.org/packages/63/c5/b21cde720f54a1d1db71538c0bc9b73dee4b563a7dd7d2e404914904d7f5/ruff-0.12.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6f4064c69d2542029b2a61d39920c85240c39837599d7f2e32e80d36401d6e", size = 13468783, upload-time = "2025-08-21T18:22:42.559Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/39369e6ac7f2a1848f22fb0b00b690492f20811a1ac5c1fd1d2798329263/ruff-0.12.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:059e863ea3a9ade41407ad71c1de2badfbe01539117f38f763ba42a1206f7559", size = 14436642, upload-time = "2025-08-21T18:22:45.612Z" }, + { url = "https://files.pythonhosted.org/packages/e3/03/5da8cad4b0d5242a936eb203b58318016db44f5c5d351b07e3f5e211bb89/ruff-0.12.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bef6161e297c68908b7218fa6e0e93e99a286e5ed9653d4be71e687dff101cf", size = 13859107, upload-time = "2025-08-21T18:22:48.886Z" }, + { url = "https://files.pythonhosted.org/packages/19/19/dd7273b69bf7f93a070c9cec9494a94048325ad18fdcf50114f07e6bf417/ruff-0.12.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f1345fbf8fb0531cd722285b5f15af49b2932742fc96b633e883da8d841896b", size = 12886521, upload-time = "2025-08-21T18:22:51.567Z" }, + { url = "https://files.pythonhosted.org/packages/c0/1d/b4207ec35e7babaee62c462769e77457e26eb853fbdc877af29417033333/ruff-0.12.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f68433c4fbc63efbfa3ba5db31727db229fa4e61000f452c540474b03de52a9", size = 13097528, upload-time = "2025-08-21T18:22:54.609Z" }, + { url = "https://files.pythonhosted.org/packages/ff/00/58f7b873b21114456e880b75176af3490d7a2836033779ca42f50de3b47a/ruff-0.12.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:141ce3d88803c625257b8a6debf4a0473eb6eed9643a6189b68838b43e78165a", size = 13080443, upload-time = "2025-08-21T18:22:57.413Z" }, + { url = "https://files.pythonhosted.org/packages/12/8c/9e6660007fb10189ccb78a02b41691288038e51e4788bf49b0a60f740604/ruff-0.12.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f3fc21178cd44c98142ae7590f42ddcb587b8e09a3b849cbc84edb62ee95de60", size = 11896759, upload-time = "2025-08-21T18:23:00.473Z" }, + { url = "https://files.pythonhosted.org/packages/67/4c/6d092bb99ea9ea6ebda817a0e7ad886f42a58b4501a7e27cd97371d0ba54/ruff-0.12.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7d1a4e0bdfafcd2e3e235ecf50bf0176f74dd37902f241588ae1f6c827a36c56", size = 11701463, upload-time = "2025-08-21T18:23:03.211Z" }, + { url = "https://files.pythonhosted.org/packages/59/80/d982c55e91df981f3ab62559371380616c57ffd0172d96850280c2b04fa8/ruff-0.12.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e67d96827854f50b9e3e8327b031647e7bcc090dbe7bb11101a81a3a2cbf1cc9", size = 12691603, upload-time = "2025-08-21T18:23:06.935Z" }, + { url = "https://files.pythonhosted.org/packages/ad/37/63a9c788bbe0b0850611669ec6b8589838faf2f4f959647f2d3e320383ae/ruff-0.12.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ae479e1a18b439c59138f066ae79cc0f3ee250712a873d00dbafadaad9481e5b", size = 13164356, upload-time = "2025-08-21T18:23:10.225Z" }, + { url = "https://files.pythonhosted.org/packages/47/d4/1aaa7fb201a74181989970ebccd12f88c0fc074777027e2a21de5a90657e/ruff-0.12.10-py3-none-win32.whl", hash = "sha256:9de785e95dc2f09846c5e6e1d3a3d32ecd0b283a979898ad427a9be7be22b266", size = 11896089, upload-time = "2025-08-21T18:23:14.232Z" }, + { url = "https://files.pythonhosted.org/packages/ad/14/2ad38fd4037daab9e023456a4a40ed0154e9971f8d6aed41bdea390aabd9/ruff-0.12.10-py3-none-win_amd64.whl", hash = "sha256:7837eca8787f076f67aba2ca559cefd9c5cbc3a9852fd66186f4201b87c1563e", size = 13004616, upload-time = "2025-08-21T18:23:17.422Z" }, + { url = "https://files.pythonhosted.org/packages/24/3c/21cf283d67af33a8e6ed242396863af195a8a6134ec581524fd22b9811b6/ruff-0.12.10-py3-none-win_arm64.whl", hash = "sha256:cc138cc06ed9d4bfa9d667a65af7172b47840e1a98b02ce7011c391e54635ffc", size = 12074225, upload-time = "2025-08-21T18:23:20.137Z" }, +] + [[package]] name = "scratchgpt" version = "0.2.0" @@ -858,11 +785,9 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "bandit" }, - { name = "black" }, - { name = "isort" }, { name = "mypy" }, - { name = "pylint" }, { name = "pytest" }, + { name = "ruff" }, ] [package.metadata] @@ -880,11 +805,9 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "bandit", specifier = ">=1.8.6" }, - { name = "black", specifier = ">=25.1.0" }, - { name = "isort", specifier = ">=6.0.1" }, { name = "mypy", specifier = ">=1.17.1" }, - { name = "pylint", specifier = ">=3.3.8" }, { name = "pytest", specifier = ">=8.4.1" }, + { name = "ruff", specifier = ">=0.1.0" }, ] [[package]] @@ -941,15 +864,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/79/bcf350609f3a10f09fe4fc207f132085e497fdd3612f3925ab24d86a0ca0/tiktoken-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:2177ffda31dec4023356a441793fed82f7af5291120751dee4d696414f54db0c", size = 883901, upload-time = "2025-08-08T23:57:59.359Z" }, ] -[[package]] -name = "tomlkit" -version = "0.13.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, -] - [[package]] name = "torch" version = "2.8.0"