From 51a48f532d47e648690662002feb4c0ca3e097d0 Mon Sep 17 00:00:00 2001 From: ed cuss Date: Wed, 5 Nov 2025 19:11:47 +0000 Subject: [PATCH 1/3] fix: add generic for result types --- src/spaghettree/core/result.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spaghettree/core/result.py b/src/spaghettree/core/result.py index f314304..06c8865 100644 --- a/src/spaghettree/core/result.py +++ b/src/spaghettree/core/result.py @@ -20,7 +20,7 @@ @attrs.define -class Ok: +class Ok[T]: inner: Any = attrs.field(default=None) def is_ok(self) -> Literal[True]: @@ -34,7 +34,7 @@ def unwrap(self) -> T: @attrs.define -class Err: +class Err[T]: input_args: Any = attrs.field(repr=False) error: Exception | None = attrs.field( default=None, @@ -75,7 +75,7 @@ def unwrap(self) -> None: raise self.error -Result = Ok | Err +Result = Ok[T] | Err[T] def safe[**P, T](func: Callable[P, T]) -> Callable[P, Result]: From ef4d7913196f20d6dbe6e6b043fcb7ad05ebb023 Mon Sep 17 00:00:00 2001 From: ed cuss Date: Wed, 5 Nov 2025 19:45:01 +0000 Subject: [PATCH 2/3] feat: extract method for analyse_existing_structure --- src/spaghettree/__main__.py | 26 ++++---------------------- src/spaghettree/core/result.py | 2 +- src/spaghettree/domain/processing.py | 27 +++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/spaghettree/__main__.py b/src/spaghettree/__main__.py index 4870a6a..efeefae 100644 --- a/src/spaghettree/__main__.py +++ b/src/spaghettree/__main__.py @@ -1,22 +1,15 @@ import argparse -import json -from pathlib import Path from spaghettree.adapters.io_wrapper import IOBase, IOWrapper from spaghettree.core.logger import logger from spaghettree.core.result import Result -from spaghettree.domain.optimisation import ( - AdjMat, - get_dwm, - get_top_suggested_merges, - yellow, -) from spaghettree.domain.parsing import ( create_call_tree, extract_entities_and_locations, filter_non_native_calls, ) from spaghettree.domain.processing import ( + analyse_existing_structure, optimise_entity_positions, ) @@ -65,20 +58,9 @@ def run_process( new_root=new_root, ).unwrap() else: - # remove any new_root so that it doesn't try to use ruff on the json - new_root = "" - adj_mat = AdjMat.from_call_tree(call_tree, optimise=optimise_src_code).unwrap() - print( # noqa: T201 - yellow( - f"Current Directed Weighted Modularity (DWM): {get_dwm(adj_mat.mat, adj_mat.communities): .5f}" - ) - ) - top_merges = get_top_suggested_merges(adj_mat).unwrap() - - for merge in top_merges: - merge.display() - - res = {Path(call_tree_save_path).absolute(): json.dumps(call_tree, indent=4)} + res, new_root = analyse_existing_structure( + call_tree, call_tree_save_path, optimise_src_code=optimise_src_code + ).unwrap() return io.write_files(res, ruff_root=new_root, format_bulk=optimise_src_code) diff --git a/src/spaghettree/core/result.py b/src/spaghettree/core/result.py index 06c8865..37c6cad 100644 --- a/src/spaghettree/core/result.py +++ b/src/spaghettree/core/result.py @@ -80,7 +80,7 @@ def unwrap(self) -> None: def safe[**P, T](func: Callable[P, T]) -> Callable[P, Result]: @functools.wraps(func) - def wrapper(*args: P.args, **kwargs: P.kwargs) -> Result: + def wrapper(*args: P.args, **kwargs: P.kwargs) -> Result[T]: try: return Ok(func(*args, **kwargs)) except Exception as e: # noqa: BLE001 diff --git a/src/spaghettree/domain/processing.py b/src/spaghettree/domain/processing.py index 554ad52..72002b1 100644 --- a/src/spaghettree/domain/processing.py +++ b/src/spaghettree/domain/processing.py @@ -1,14 +1,20 @@ +import json import os from collections import Counter, defaultdict from copy import deepcopy +from pathlib import Path +from typing import Literal from spaghettree.core.logger import logger from spaghettree.core.result import Result, safe from spaghettree.domain.entities import EntityCST, ImportCST, ImportType from spaghettree.domain.optimisation import ( AdjMat, + get_dwm, + get_top_suggested_merges, merge_single_entity_communities_if_no_gain_penalty, optimise_communities, + yellow, ) from spaghettree.domain.parsing import ( cst_to_str, @@ -42,6 +48,27 @@ def optimise_entity_positions( ) +@safe +def analyse_existing_structure( + call_tree: dict[str, list[str]], call_tree_save_path: str, *, optimise_src_code: bool +) -> tuple[dict[Path, str], Literal[""]]: + adj_mat = AdjMat.from_call_tree(call_tree, optimise=optimise_src_code).unwrap() + print( # noqa: T201 + yellow( + f"Current Directed Weighted Modularity (DWM): {get_dwm(adj_mat.mat, adj_mat.communities): .5f}" + ) + ) + top_merges = get_top_suggested_merges(adj_mat).unwrap() + + for merge in top_merges: + merge.display() + + # remove any new_root so that it doesn't try to use ruff on the json + new_root = "" + res: dict[Path, str] = {Path(call_tree_save_path).absolute(): json.dumps(call_tree, indent=4)} + return res, new_root + + @safe def create_new_module_map( adj_mat: AdjMat, From 601c7d2b2430686bedf69a9847b995dfc21fbdc9 Mon Sep 17 00:00:00 2001 From: ed cuss Date: Mon, 24 Nov 2025 20:54:20 +0000 Subject: [PATCH 3/3] feat: add danom as dep --- README.md | 6 +- pyproject.toml | 5 +- src/spaghettree/__main__.py | 3 +- src/spaghettree/adapters/io_wrapper.py | 4 +- src/spaghettree/core/result.py | 97 -------------------------- src/spaghettree/domain/optimisation.py | 2 +- src/spaghettree/domain/parsing.py | 2 +- src/spaghettree/domain/processing.py | 3 +- tests/core/test_result.py | 18 ----- uv.lock | 30 ++++++-- 10 files changed, 38 insertions(+), 132 deletions(-) delete mode 100644 src/spaghettree/core/result.py delete mode 100644 tests/core/test_result.py diff --git a/README.md b/README.md index bb94d65..eb442f6 100644 --- a/README.md +++ b/README.md @@ -154,8 +154,7 @@ class SomeOtherClass: │ │ └── io_wrapper.py │ ├── core │ │ ├── __init__.py -│ │ ├── logger.py -│ │ └── result.py +│ │ └── logger.py │ ├── domain │ │ ├── __init__.py │ │ ├── entities.py @@ -170,8 +169,7 @@ class SomeOtherClass: │ │ ├── __init__.py │ │ └── test_adapter_apis.py │ ├── core -│ │ ├── __init__.py -│ │ └── test_result.py +│ │ └── __init__.py │ ├── domain │ │ ├── __init__.py │ │ ├── test_entities.py diff --git a/pyproject.toml b/pyproject.toml index cefdd02..46bb963 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,8 +8,9 @@ authors = [ ] requires-python = ">=3.12" dependencies = [ - "attrs>=25.1.0", + "attrs>=25.4.0", "black>=25.1.0", + "danom>=0.1.0", "isort>=6.0.1", "libcst>=1.6.0", "numpy>=2.3.2", @@ -36,7 +37,7 @@ dev = [ "ruff>=0.9.9", ] research = [ - "attrs==25.1.0", + "attrs==25.4.0", "black==25.1.0", "faker==37.1.0", "fastapi==0.115.12", diff --git a/src/spaghettree/__main__.py b/src/spaghettree/__main__.py index efeefae..dde2e6f 100644 --- a/src/spaghettree/__main__.py +++ b/src/spaghettree/__main__.py @@ -1,8 +1,9 @@ import argparse +from danom import Result + from spaghettree.adapters.io_wrapper import IOBase, IOWrapper from spaghettree.core.logger import logger -from spaghettree.core.result import Result from spaghettree.domain.parsing import ( create_call_tree, extract_entities_and_locations, diff --git a/src/spaghettree/adapters/io_wrapper.py b/src/spaghettree/adapters/io_wrapper.py index f8e912c..c231460 100644 --- a/src/spaghettree/adapters/io_wrapper.py +++ b/src/spaghettree/adapters/io_wrapper.py @@ -7,10 +7,10 @@ import attrs import black import isort +from danom import Err, Ok, Result, safe from ruff.__main__ import find_ruff_bin from spaghettree.core.logger import logger -from spaghettree.core.result import Err, Ok, Result, safe from spaghettree.domain.optimisation import yellow @@ -50,7 +50,7 @@ def write(self, modified_code: str, filepath: str, *, format_code: bool = True) def _run_ruff(self, path: str) -> None: pass - def read_files(self, root: str | Path) -> Result: + def read_files(self, root: str | Path) -> Result[dict[str, str], dict[str, Err]]: paths_res = self.list_files(root) if not paths_res.is_ok(): return paths_res diff --git a/src/spaghettree/core/result.py b/src/spaghettree/core/result.py deleted file mode 100644 index 37c6cad..0000000 --- a/src/spaghettree/core/result.py +++ /dev/null @@ -1,97 +0,0 @@ -from __future__ import annotations - -import functools -from collections.abc import Callable -from types import TracebackType -from typing import ( - Any, - Literal, - ParamSpec, - Self, - TypeVar, -) - -import attrs - -from spaghettree.core.logger import logger - -T = TypeVar("T") -P = ParamSpec("P") - - -@attrs.define -class Ok[T]: - inner: Any = attrs.field(default=None) - - def is_ok(self) -> Literal[True]: - return True - - def and_then(self, func: Callable[[T], Result], **kwargs: dict) -> Result: - return func(self.inner, **kwargs) - - def unwrap(self) -> T: - return self.inner - - -@attrs.define -class Err[T]: - input_args: Any = attrs.field(repr=False) - error: Exception | None = attrs.field( - default=None, - validator=attrs.validators.optional(attrs.validators.instance_of(Exception)), - ) - err_type: BaseException = attrs.field(init=False, repr=False) - err_msg: str = attrs.field(init=False, repr=False) - details: list[dict[str, Any]] = attrs.field(init=False, repr=False) - - def __attrs_post_init__(self) -> None: - self.err_type = type(self.error) - self.err_msg = str(self.error) - if self.error: - self.details = self._extract_details(self.error.__traceback__) - - def _extract_details(self, tb: TracebackType | None) -> list[dict[str, Any]]: - trace_info = [] - while tb: - frame = tb.tb_frame - trace_info.append( - { - "file": frame.f_code.co_filename, - "func": frame.f_code.co_name, - "line_no": tb.tb_lineno, - "locals": frame.f_locals, - }, - ) - tb = tb.tb_next - return trace_info - - def is_ok(self) -> Literal[False]: - return False - - def and_then(self, _: Callable[[T], Result], **_kwargs: dict) -> Self: - return self - - def unwrap(self) -> None: - raise self.error - - -Result = Ok[T] | Err[T] - - -def safe[**P, T](func: Callable[P, T]) -> Callable[P, Result]: - @functools.wraps(func) - def wrapper(*args: P.args, **kwargs: P.kwargs) -> Result[T]: - try: - return Ok(func(*args, **kwargs)) - except Exception as e: # noqa: BLE001 - logger.error(f"{args = } {kwargs = } {e = }") - return Err((args, kwargs), e) - - return wrapper - - -__all__ = [ - "Err", - "Ok", - "Result", -] diff --git a/src/spaghettree/domain/optimisation.py b/src/spaghettree/domain/optimisation.py index a636851..d71c199 100644 --- a/src/spaghettree/domain/optimisation.py +++ b/src/spaghettree/domain/optimisation.py @@ -6,9 +6,9 @@ import attrs import numpy as np +from danom import safe from spaghettree.core.logger import logger -from spaghettree.core.result import safe @attrs.define diff --git a/src/spaghettree/domain/parsing.py b/src/spaghettree/domain/parsing.py index dd9bc8a..5562e6b 100644 --- a/src/spaghettree/domain/parsing.py +++ b/src/spaghettree/domain/parsing.py @@ -7,10 +7,10 @@ import libcst as cst import numpy as np +from danom import safe from tqdm import tqdm from spaghettree.core.logger import logger -from spaghettree.core.result import safe from spaghettree.domain.entities import EntityCST from spaghettree.domain.optimisation import AdjMat from spaghettree.domain.visitors import EntityLocation, OnePassVisitor diff --git a/src/spaghettree/domain/processing.py b/src/spaghettree/domain/processing.py index 72002b1..22d1157 100644 --- a/src/spaghettree/domain/processing.py +++ b/src/spaghettree/domain/processing.py @@ -5,8 +5,9 @@ from pathlib import Path from typing import Literal +from danom import Result, safe + from spaghettree.core.logger import logger -from spaghettree.core.result import Result, safe from spaghettree.domain.entities import EntityCST, ImportCST, ImportType from spaghettree.domain.optimisation import ( AdjMat, diff --git a/tests/core/test_result.py b/tests/core/test_result.py deleted file mode 100644 index b3bd7e0..0000000 --- a/tests/core/test_result.py +++ /dev/null @@ -1,18 +0,0 @@ -import pytest - -from spaghettree.core.result import safe - - -def test_safe(): - @safe - def raises(): - raise ValueError("An error") - - res = raises() - assert not res.is_ok() - assert list(res.details[0].keys()) == ["file", "func", "line_no", "locals"] - # make sure Err.and_then => Err - assert res.and_then(lambda x: x) == res - - with pytest.raises(ValueError): - res.unwrap() diff --git a/uv.lock b/uv.lock index 94a916f..e75e2f2 100644 --- a/uv.lock +++ b/uv.lock @@ -77,11 +77,11 @@ wheels = [ [[package]] name = "attrs" -version = "25.1.0" +version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562, upload-time = "2025-01-25T11:30:12.508Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152, upload-time = "2025-01-25T11:30:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] [[package]] @@ -640,6 +640,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/24/f7351052cf9db771fe4f32fca47fd66e6d9b53d8613b17faf7d130a9d553/cython-3.1.4-py3-none-any.whl", hash = "sha256:d194d95e4fa029a3f6c7d46bdd16d973808c7ea4797586911fdb67cb98b1a2c6", size = 1227541, upload-time = "2025-09-16T07:20:29.595Z" }, ] +[[package]] +name = "danom" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/a9/415a69c470ef688a100815f4f199c672ccd80a8561365960d50c5638b205/danom-0.1.0.tar.gz", hash = "sha256:2b6defa6948568ed4c37589bbf9d25e7ecdb47e8c82c1426cd959c6f00c87e86", size = 2006, upload-time = "2025-11-24T20:44:57.575Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/0f/5e99d99bdeb9e5a964847bf1442ae93b9077dc49c9a83f6cd3ed541d742f/danom-0.1.0-py3-none-any.whl", hash = "sha256:8ed5412079a0beb8408e615f3ec0e56985e820d9c80780f5f57c1d21046aa574", size = 3805, upload-time = "2025-11-24T20:44:56.438Z" }, +] + [[package]] name = "debugpy" version = "1.8.17" @@ -1019,6 +1031,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" }, { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" }, { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" }, + { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" }, + { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" }, { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" }, { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, @@ -1028,6 +1042,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, + { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" }, + { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" }, { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, @@ -1035,6 +1051,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" }, + { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" }, { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, ] @@ -3025,6 +3043,7 @@ source = { editable = "." } dependencies = [ { name = "attrs" }, { name = "black" }, + { name = "danom" }, { name = "isort" }, { name = "libcst" }, { name = "numpy" }, @@ -3078,8 +3097,9 @@ research = [ [package.metadata] requires-dist = [ - { name = "attrs", specifier = ">=25.1.0" }, + { name = "attrs", specifier = ">=25.4.0" }, { name = "black", specifier = ">=25.1.0" }, + { name = "danom", specifier = ">=0.1.0" }, { name = "isort", specifier = ">=6.0.1" }, { name = "libcst", specifier = ">=1.6.0" }, { name = "numpy", specifier = ">=2.3.2" }, @@ -3099,7 +3119,7 @@ dev = [ { name = "ruff", specifier = ">=0.9.9" }, ] research = [ - { name = "attrs", specifier = "==25.1.0" }, + { name = "attrs", specifier = "==25.4.0" }, { name = "beartype", specifier = "==0.20.2" }, { name = "black", specifier = "==25.1.0" }, { name = "class-inspector", specifier = "==0.3.1" },