From a7fccd43e4dd41285e3eb4a3963548291ae62cce Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 15:52:56 -0400 Subject: [PATCH 01/24] PATCH: move logging configuration inside of the package --- .python-version | 1 + pyproject.toml | 40 +++++++++----------- src/FragmentRetro/utils/logging_config.py | 46 ++++++++++++++++------- 3 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 .python-version diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..d367df0 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12.10 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d5f9412..5ebdcaa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,8 @@ [project] name = "fragment" version = "0.0.1" +requires-python = ">=3.12" +readme = "README.md" dependencies = [ "numpy==1.26.4", "rdkit==2023.9.3", @@ -12,6 +14,20 @@ dependencies = [ "ipywidgets==8.1.6", "ipykernel>=6.29.5", ] +authors = [ + { name = "Yu Shee", email = "yu.shee@yale.edu" }, + { name = "Anton Morgunov", email = "anton@ischemist.com" }, +] +license = { text = "MIT" } + +[project.urls] +Homepage = "https://github.com/randyshee/FragmentRetro" +Issues = "https://github.com/randyshee/FragmentRetro/issues" + + +[tool.setuptools] +package-dir = { "" = "src" } + [project.optional-dependencies] @@ -32,32 +48,10 @@ strict = true ignore_missing_imports = true exclude = ["tests", "src/fragmentation/rBRICS.py"] disable_error_code = ["unused-ignore"] + [[tool.mypy.overrides]] module = ["rdkit-stubs.*", "rdkit.*"] ignore_errors = true [tool.ruff] line-length = 120 - -[tool.logging] -version = 1 -disable_existing_loggers = false - -[tool.logging.formatters.standard] -format = "%(asctime)s [%(levelname)s] %(name)s: %(message)s" -datefmt = "%Y-%m-%d %H:%M:%S" - -[tool.logging.handlers.console] -class = "logging.StreamHandler" -formatter = "standard" -stream = "ext://sys.stdout" - -[tool.logging.loggers.fragment] -handlers = ["console"] -propagate = false -level = "INFO" - -[tool.logging.loggers.app] -handlers = ["console"] -propagate = false -level = "INFO" \ No newline at end of file diff --git a/src/FragmentRetro/utils/logging_config.py b/src/FragmentRetro/utils/logging_config.py index 3b6a8ee..54bf260 100644 --- a/src/FragmentRetro/utils/logging_config.py +++ b/src/FragmentRetro/utils/logging_config.py @@ -1,17 +1,38 @@ import logging import logging.config import os -from pathlib import Path - -import tomli +from typing import Any + +# --- Hardcoded Configuration --- +LOGGING_CONFIG: dict[str, Any] = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "standard": { + "format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s", + "datefmt": "%Y-%m-%d %H:%M:%S", + } + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "formatter": "standard", + "stream": "ext://sys.stdout", + } + }, + "loggers": { + "fragment": { + "handlers": ["console"], + "propagate": False, + "level": "INFO", # Default level + } + }, +} +# --- End Hardcoded Configuration --- def setup_logging() -> None: - """Setup logging configuration from pyproject.toml with environment variable override""" - pyproject_path = Path(__file__).parents[3] / "pyproject.toml" - - with open(pyproject_path, "rb") as f: - config = tomli.load(f) + """Setup logging configuration from hardcoded dict with environment variable override""" # Get log level from environment variable, default to INFO if not set log_level = os.getenv("FRAGMENT_LOG_LEVEL", "INFO").upper() @@ -20,13 +41,12 @@ def setup_logging() -> None: valid_levels = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} if log_level not in valid_levels: print(f"Invalid log level {log_level}, defaulting to INFO") - log_level = "INFO" + log_level = "INFO" # Make sure to reset if invalid - # Override the log level from config - logging_config = config["tool"]["logging"] - logging_config["loggers"]["fragment"]["level"] = log_level + # Override the log level in the copied config + LOGGING_CONFIG["loggers"]["fragment"]["level"] = log_level - logging.config.dictConfig(logging_config) + logging.config.dictConfig(LOGGING_CONFIG) logger = logging.getLogger("fragment") From a92442ce2f07e712970a7a48dc4973f7b5e1d2a2 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 15:59:23 -0400 Subject: [PATCH 02/24] DEV: bring back old name --- pyproject.toml | 13 ++++++++ src/app/__init__.py | 5 --- src/app/logging_config.py | 32 ------------------- .../__init__.py | 0 .../utils => fragmentretro/app}/__init__.py | 0 src/{ => fragmentretro}/app/gui/__init__.py | 0 src/{ => fragmentretro}/app/gui/controller.py | 10 +++--- src/{ => fragmentretro}/app/gui/layout.py | 1 - src/{ => fragmentretro}/app/gui/state.py | 0 src/{ => fragmentretro}/app/gui/widgets.py | 0 src/{ => fragmentretro}/app/interface.py | 3 +- .../fragmentation/__init__.py | 0 .../fragmentation/r_brics.py} | 0 .../fragmenter.py | 2 +- .../fragmenter_base.py | 0 .../retrosynthesis.py | 0 .../solutions.py | 0 .../substructure_matcher.py | 0 src/fragmentretro/utils/__init__.py | 0 .../utils/filter_compound.py | 0 .../utils/helpers.py | 0 .../utils/logging_config.py | 0 .../utils/type_definitions.py | 0 23 files changed, 20 insertions(+), 46 deletions(-) delete mode 100644 src/app/__init__.py delete mode 100644 src/app/logging_config.py rename src/{FragmentRetro => fragmentretro}/__init__.py (100%) rename src/{FragmentRetro/utils => fragmentretro/app}/__init__.py (100%) rename src/{ => fragmentretro}/app/gui/__init__.py (100%) rename src/{ => fragmentretro}/app/gui/controller.py (100%) rename src/{ => fragmentretro}/app/gui/layout.py (99%) rename src/{ => fragmentretro}/app/gui/state.py (100%) rename src/{ => fragmentretro}/app/gui/widgets.py (100%) rename src/{ => fragmentretro}/app/interface.py (99%) rename src/{ => fragmentretro}/fragmentation/__init__.py (100%) rename src/{fragmentation/rBRICS.py => fragmentretro/fragmentation/r_brics.py} (100%) rename src/{FragmentRetro => fragmentretro}/fragmenter.py (100%) rename src/{FragmentRetro => fragmentretro}/fragmenter_base.py (100%) rename src/{FragmentRetro => fragmentretro}/retrosynthesis.py (100%) rename src/{FragmentRetro => fragmentretro}/solutions.py (100%) rename src/{FragmentRetro => fragmentretro}/substructure_matcher.py (100%) create mode 100644 src/fragmentretro/utils/__init__.py rename src/{FragmentRetro => fragmentretro}/utils/filter_compound.py (100%) rename src/{FragmentRetro => fragmentretro}/utils/helpers.py (100%) rename src/{FragmentRetro => fragmentretro}/utils/logging_config.py (100%) rename src/{FragmentRetro => fragmentretro}/utils/type_definitions.py (100%) diff --git a/pyproject.toml b/pyproject.toml index 5ebdcaa..dcdd7de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,3 +55,16 @@ ignore_errors = true [tool.ruff] line-length = 120 +# lint.select = [ +# "E", # pycodestyle +# "F", # Pyflakes +# "UP", # pyupgrade +# "B", # flake8-bugbear +# "SIM", # flake8-simplify +# "I", # isort +# ] +# lint.ignore = [ +# "E501", # o respect fmt off blocks +# "SIM108", # disagree w/ https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp/ +# ] +# exclude = ["tests"] \ No newline at end of file diff --git a/src/app/__init__.py b/src/app/__init__.py deleted file mode 100644 index afc0082..0000000 --- a/src/app/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""FragmentRetro App""" - -from app.logging_config import setup_logging - -setup_logging() diff --git a/src/app/logging_config.py b/src/app/logging_config.py deleted file mode 100644 index bd330dd..0000000 --- a/src/app/logging_config.py +++ /dev/null @@ -1,32 +0,0 @@ -import logging -import logging.config -import os -from pathlib import Path - -import tomli - - -def setup_logging() -> None: - """Setup logging configuration from pyproject.toml with environment variable override""" - pyproject_path = Path(__file__).parents[2] / "pyproject.toml" - - with open(pyproject_path, "rb") as f: - config = tomli.load(f) - - # Get log level from environment variable, default to INFO if not set - log_level = os.getenv("APP_LOG_LEVEL", "INFO").upper() - - # Validate the log level - valid_levels = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} - if log_level not in valid_levels: - print(f"Invalid log level {log_level}, defaulting to INFO") - log_level = "INFO" - - # Override the log level from config - logging_config = config["tool"]["logging"] - logging_config["loggers"]["fragment"]["level"] = log_level - - logging.config.dictConfig(logging_config) - - -logger = logging.getLogger("app") diff --git a/src/FragmentRetro/__init__.py b/src/fragmentretro/__init__.py similarity index 100% rename from src/FragmentRetro/__init__.py rename to src/fragmentretro/__init__.py diff --git a/src/FragmentRetro/utils/__init__.py b/src/fragmentretro/app/__init__.py similarity index 100% rename from src/FragmentRetro/utils/__init__.py rename to src/fragmentretro/app/__init__.py diff --git a/src/app/gui/__init__.py b/src/fragmentretro/app/gui/__init__.py similarity index 100% rename from src/app/gui/__init__.py rename to src/fragmentretro/app/gui/__init__.py diff --git a/src/app/gui/controller.py b/src/fragmentretro/app/gui/controller.py similarity index 100% rename from src/app/gui/controller.py rename to src/fragmentretro/app/gui/controller.py index 9f4868f..4e265f6 100644 --- a/src/app/gui/controller.py +++ b/src/fragmentretro/app/gui/controller.py @@ -3,11 +3,6 @@ from typing import cast import ipywidgets as widgets -from IPython.display import display -from PIL.Image import Image as PILImage -from rdkit import Chem -from rdkit.Chem import Draw - from app.gui.state import AppState from app.gui.widgets import ( core_factor_input, @@ -32,6 +27,11 @@ target_smiles_input, ) from app.logging_config import logger +from IPython.display import display +from PIL.Image import Image as PILImage +from rdkit import Chem +from rdkit.Chem import Draw + from FragmentRetro.fragmenter import BRICSFragmenter, rBRICSFragmenter from FragmentRetro.fragmenter_base import Fragmenter from FragmentRetro.retrosynthesis import Retrosynthesis diff --git a/src/app/gui/layout.py b/src/fragmentretro/app/gui/layout.py similarity index 99% rename from src/app/gui/layout.py rename to src/fragmentretro/app/gui/layout.py index aee04fa..c77e4b8 100644 --- a/src/app/gui/layout.py +++ b/src/fragmentretro/app/gui/layout.py @@ -1,5 +1,4 @@ import ipywidgets as widgets - from app.gui.widgets import ( core_factor_input, display_button, diff --git a/src/app/gui/state.py b/src/fragmentretro/app/gui/state.py similarity index 100% rename from src/app/gui/state.py rename to src/fragmentretro/app/gui/state.py diff --git a/src/app/gui/widgets.py b/src/fragmentretro/app/gui/widgets.py similarity index 100% rename from src/app/gui/widgets.py rename to src/fragmentretro/app/gui/widgets.py diff --git a/src/app/interface.py b/src/fragmentretro/app/interface.py similarity index 99% rename from src/app/interface.py rename to src/fragmentretro/app/interface.py index 9556799..9fc1cf0 100644 --- a/src/app/interface.py +++ b/src/fragmentretro/app/interface.py @@ -1,9 +1,8 @@ -from IPython.display import display - from app.gui.controller import GuiController from app.gui.layout import gui_layout from app.gui.state import AppState from app.gui.widgets import target_smiles_input +from IPython.display import display # --- Main Function to Display GUI --- diff --git a/src/fragmentation/__init__.py b/src/fragmentretro/fragmentation/__init__.py similarity index 100% rename from src/fragmentation/__init__.py rename to src/fragmentretro/fragmentation/__init__.py diff --git a/src/fragmentation/rBRICS.py b/src/fragmentretro/fragmentation/r_brics.py similarity index 100% rename from src/fragmentation/rBRICS.py rename to src/fragmentretro/fragmentation/r_brics.py diff --git a/src/FragmentRetro/fragmenter.py b/src/fragmentretro/fragmenter.py similarity index 100% rename from src/FragmentRetro/fragmenter.py rename to src/fragmentretro/fragmenter.py index 56c48fa..68cd746 100644 --- a/src/FragmentRetro/fragmenter.py +++ b/src/fragmentretro/fragmenter.py @@ -1,9 +1,9 @@ """Module for fragmenting molecules using BRICS (add other algorithms later).""" +from fragmentation.rBRICS import BreakrBRICSBonds, FindrBRICSBonds from rdkit.Chem import Mol from rdkit.Chem.BRICS import BreakBRICSBonds, FindBRICSBonds -from fragmentation.rBRICS import BreakrBRICSBonds, FindrBRICSBonds from FragmentRetro.fragmenter_base import Fragmenter from FragmentRetro.utils.type_definitions import BondType diff --git a/src/FragmentRetro/fragmenter_base.py b/src/fragmentretro/fragmenter_base.py similarity index 100% rename from src/FragmentRetro/fragmenter_base.py rename to src/fragmentretro/fragmenter_base.py diff --git a/src/FragmentRetro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py similarity index 100% rename from src/FragmentRetro/retrosynthesis.py rename to src/fragmentretro/retrosynthesis.py diff --git a/src/FragmentRetro/solutions.py b/src/fragmentretro/solutions.py similarity index 100% rename from src/FragmentRetro/solutions.py rename to src/fragmentretro/solutions.py diff --git a/src/FragmentRetro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py similarity index 100% rename from src/FragmentRetro/substructure_matcher.py rename to src/fragmentretro/substructure_matcher.py diff --git a/src/fragmentretro/utils/__init__.py b/src/fragmentretro/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/FragmentRetro/utils/filter_compound.py b/src/fragmentretro/utils/filter_compound.py similarity index 100% rename from src/FragmentRetro/utils/filter_compound.py rename to src/fragmentretro/utils/filter_compound.py diff --git a/src/FragmentRetro/utils/helpers.py b/src/fragmentretro/utils/helpers.py similarity index 100% rename from src/FragmentRetro/utils/helpers.py rename to src/fragmentretro/utils/helpers.py diff --git a/src/FragmentRetro/utils/logging_config.py b/src/fragmentretro/utils/logging_config.py similarity index 100% rename from src/FragmentRetro/utils/logging_config.py rename to src/fragmentretro/utils/logging_config.py diff --git a/src/FragmentRetro/utils/type_definitions.py b/src/fragmentretro/utils/type_definitions.py similarity index 100% rename from src/FragmentRetro/utils/type_definitions.py rename to src/fragmentretro/utils/type_definitions.py From 7aca17c4256b0ec34c1ecbfa1792a63b7e94b6b9 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:10:39 -0400 Subject: [PATCH 03/24] jesus fucking christ, rdkit is going to make you suicidal --- pyproject.toml | 4 +- src/fragmentretro/exceptions.py | 10 + src/fragmentretro/fragmentation/r_brics.py | 329 ++++++++++++--------- src/fragmentretro/fragmenter.py | 10 +- 4 files changed, 212 insertions(+), 141 deletions(-) create mode 100644 src/fragmentretro/exceptions.py diff --git a/pyproject.toml b/pyproject.toml index dcdd7de..99a0569 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "fragment" +name = "fragmentretro" version = "0.0.1" requires-python = ">=3.12" readme = "README.md" @@ -46,7 +46,7 @@ dev = [ [tool.mypy] strict = true ignore_missing_imports = true -exclude = ["tests", "src/fragmentation/rBRICS.py"] +exclude = ["tests", "src/fragmentation/r_brics.py"] disable_error_code = ["unused-ignore"] [[tool.mypy.overrides]] diff --git a/src/fragmentretro/exceptions.py b/src/fragmentretro/exceptions.py new file mode 100644 index 0000000..f14f93f --- /dev/null +++ b/src/fragmentretro/exceptions.py @@ -0,0 +1,10 @@ +class FragmentRetroError(Exception): + """Base class for all exceptions in FragmentRetro.""" + + pass + + +class SmartsParsingError(FragmentRetroError, ValueError): + """Error raised when a SMARTS string is parsed incorrectly.""" + + pass diff --git a/src/fragmentretro/fragmentation/r_brics.py b/src/fragmentretro/fragmentation/r_brics.py index 0bdcfd1..619d928 100644 --- a/src/fragmentretro/fragmentation/r_brics.py +++ b/src/fragmentretro/fragmentation/r_brics.py @@ -45,12 +45,40 @@ import copy import random import re +from typing import Generator from rdkit import Chem from rdkit.Chem import rdChemReactions as Reactions +from fragmentretro.exceptions import SmartsParsingError + +type EnvironmentLabel = str +type SmartsPattern = str +type BondTypeSpecifier = str + +type EnvironmentSmartsMap = dict[EnvironmentLabel, SmartsPattern] + +type BondCleavageRule = tuple[EnvironmentLabel, EnvironmentLabel, BondTypeSpecifier] +type BondCleavageRuleGroup = list[BondCleavageRule] +type BondCleavageDefinitions = tuple[BondCleavageRuleGroup, ...] + + +type RDKitMol = Chem.Mol # More explicit alias for rdkit.Chem.Mol +type RDKitReaction = Reactions.ChemicalReaction # Alias for rdkit reaction object + +type EnvironmentMolMatchersMap = dict[EnvironmentLabel, RDKitMol] + +type BondMatcherRule = tuple[EnvironmentLabel, EnvironmentLabel, BondTypeSpecifier, RDKitMol] +type BondMatcherList = list[list[BondMatcherRule]] + +# Type for a list of RDKit reaction objects +type ReactionList = list[RDKitReaction] +# Type for the grouped forward reactions +type ReactionGroups = tuple[ReactionList, ...] + + # These are the definitions that will be applied to fragment molecules: -environs = { +environs: EnvironmentSmartsMap = { "L1": "[C;D3]([#0,#6,#7,#8])(=O)", # # After some discussion, the L2 definitions ("N.pl3" in the original @@ -110,7 +138,7 @@ #'L51':'[N;!R;!D1;$(N(!@[N,O]))]', #duplication for record #'L81':'[C;!R;!D1;$(C(-[C,N,O,S])(=[N,S]))]', #duplication for record } -reactionDefs = ( +reaction_defs: BondCleavageDefinitions = ( # L1 [ ("1", "3", "-"), @@ -318,109 +346,128 @@ [("22", "23", "-")], ) -reactionDefs_r = ([("20", "21", "-")],) +reaction_defs_r: BondCleavageDefinitions = ([("20", "21", "-")],) -def init_reactions(environs, reactionDefs): - smartsGps = copy.deepcopy(reactionDefs) - for gp in smartsGps: - for j, defn in enumerate(gp): - g1, g2, bnd = defn - r1 = environs["L" + g1] - r2 = environs["L" + g2] - g1 = re.sub("[a-z,A-Z]", "", g1) - g2 = re.sub("[a-z,A-Z]", "", g2) - if "@" not in bnd: # Leili +def initialize_env_matchers(environments: EnvironmentSmartsMap) -> EnvironmentMolMatchersMap: + env_matchers = {} + for env, smarts in environments.items(): + env_matchers[env] = Chem.MolFromSmarts(smarts) + return env_matchers + + +def initialize_bond_matchers( + environments: EnvironmentSmartsMap, reaction_definitions: BondCleavageDefinitions +) -> BondMatcherList: + bond_matchers = [] + for group_idx, rule_group in enumerate(reaction_definitions): + tmp = [] + for env_idx1, env_idx2, bond in rule_group: + smarts1 = environments["L%s" % env_idx1] + smarts2 = environments["L%s" % env_idx2] + if "@" in bond: # Leili + patt = "[$(%s)]%s[$(%s)]" % (smarts1, bond, smarts2) + else: + patt = "[$(%s)]%s;!@[$(%s)]" % (smarts1, bond, smarts2) + # patt = '[$(%s)]%s;!@[$(%s)]'%(e1,bType,e2) #original + patt = Chem.MolFromSmarts(patt) + tmp.append((env_idx1, env_idx2, bond, patt)) + bond_matchers.append(tmp) + return bond_matchers + + +def init_reactions( + environments: EnvironmentSmartsMap, reaction_definitions: BondCleavageDefinitions +) -> tuple[list[SmartsPattern], ReactionGroups, ReactionList]: + rule_groups = copy.deepcopy(reaction_definitions) + smarts_groups = [] + for rule_group in rule_groups: + for rule_idx, rule in enumerate(rule_group): + env_idx1, env_idx2, bond = rule + smarts1 = environs["L" + env_idx1] + smarts2 = environs["L" + env_idx2] + g1 = re.sub("[a-z,A-Z]", "", env_idx1) + g2 = re.sub("[a-z,A-Z]", "", env_idx2) + if "@" not in bond: # Leili # if 1 == 1: - sma = "[$(%s):1]%s;!@[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (r1, bnd, r2, g1, g2) + sma = "[$(%s):1]%s;!@[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (smarts1, bond, smarts2, g1, g2) else: - sma = "[$(%s):1]%s[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (r1, bnd, r2, g1, g2) - gp[j] = sma + sma = "[$(%s):1]%s[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (smarts1, bond, smarts2, g1, g2) + smarts_groups.append(sma) # sma='[$(%s):1]%s;!@[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]'%(r1,bnd,r2,g1,g2) #original # gp[j] =sma - for gp in smartsGps: - for defn in gp: + for smarts_group in smarts_groups: + for smarts in smarts_group: try: - t = Reactions.ReactionFromSmarts(defn) + t = Reactions.ReactionFromSmarts(smarts) t.Initialize() - except: - print(defn) - raise + except Exception as e: + raise SmartsParsingError(f"Failed to parse SMARTS pattern: {smarts}") from e + + reactions = tuple([[Reactions.ReactionFromSmarts(y) for y in x] for x in smarts_groups]) + reverse_reactions = [] + for group_idx, smarts_group in enumerate(smarts_groups): + for smarts_idx, smarts in enumerate(smarts_group): + reactants, products = smarts.split(">>") + smarts = "%s>>%s" % (products, reactants) + rxn = Reactions.ReactionFromSmarts(smarts) + labels = re.findall(r"\[([0-9]+?)\*\]", products) + rxn._matchers = [Chem.MolFromSmiles("[%s*]" % x) for x in labels] + reverse_reactions.append(rxn) - environMatchers = {} - for env, sma in environs.items(): - environMatchers[env] = Chem.MolFromSmarts(sma) + return smarts_groups, reactions, reverse_reactions - bondMatchers = [] - for i, compats in enumerate(reactionDefs): - tmp = [] - for i1, i2, bType in compats: - e1 = environs["L%s" % i1] - e2 = environs["L%s" % i2] - if "@" in bType: # Leili - patt = "[$(%s)]%s[$(%s)]" % (e1, bType, e2) - else: - patt = "[$(%s)]%s;!@[$(%s)]" % (e1, bType, e2) - # patt = '[$(%s)]%s;!@[$(%s)]'%(e1,bType,e2) #original - patt = Chem.MolFromSmarts(patt) - tmp.append((i1, i2, bType, patt)) - bondMatchers.append(tmp) - - reactions = tuple([[Reactions.ReactionFromSmarts(y) for y in x] for x in smartsGps]) - reverseReactions = [] - for i, rxnSet in enumerate(smartsGps): - for j, sma in enumerate(rxnSet): - rs, ps = sma.split(">>") - sma = "%s>>%s" % (ps, rs) - rxn = Reactions.ReactionFromSmarts(sma) - labels = re.findall(r"\[([0-9]+?)\*\]", ps) - rxn._matchers = [Chem.MolFromSmiles("[%s*]" % x) for x in labels] - reverseReactions.append(rxn) - return gp, environMatchers, bondMatchers, reactions, reverseReactions +smarts_groups, reactions, REVERSE_REACTIONS = init_reactions(environs, reaction_defs) +smarts_groups_r, reactions_r, REVERSE_REACTIONS_R = init_reactions(environs, reaction_defs_r) +ENV_MATCHERS = initialize_env_matchers(environs) +# AM: rBRICS had env_matchers_r, but because env matcher does not depend on reaction definitions, +# that env_matchers_r was identical to env_matchers -gp, environMatchers, bondMatchers, reactions, reverseReactions = init_reactions(environs, reactionDefs) -gp_r, environMatchers_r, bondMatchers_r, reactions_r, reverseReactions_r = init_reactions(environs, reactionDefs_r) +BOND_MATCHERS = initialize_bond_matchers(environs, reaction_defs) +BOND_MATCHERS_R = initialize_bond_matchers(environs, reaction_defs_r) -def FindrBRICSBonds(mol, randomizeOrder=False, silent=True): +def find_brics_bonds( + mol: Chem.Mol, randomizeOrder: bool = False, silent: bool = True +) -> Generator[tuple[tuple[int, int], tuple[EnvironmentLabel, EnvironmentLabel]], None, None]: """returns the bonds in a molecule that BRICS would cleave >>> from rdkit import Chem >>> m = Chem.MolFromSmiles('CCCOCC') - >>> res = list(FindrBRICSBonds(m)) + >>> res = list(find_brics_bonds(m)) >>> res [((3, 2), ('3', '4')), ((3, 4), ('3', '4'))] a more complicated case: >>> m = Chem.MolFromSmiles('CCCOCCC(=O)c1ccccc1') - >>> res = list(FindrBRICSBonds(m)) + >>> res = list(find_brics_bonds(m)) >>> res [((3, 2), ('3', '4')), ((3, 4), ('3', '4')), ((6, 8), ('6', '16'))] we can also randomize the order of the results: >>> random.seed(23) - >>> res = list(FindrBRICSBonds(m,randomizeOrder=True)) + >>> res = list(find_brics_bonds(m,randomizeOrder=True)) >>> sorted(res) [((3, 2), ('3', '4')), ((3, 4), ('3', '4')), ((6, 8), ('6', '16'))] Note that this is a generator function : - >>> res = FindrBRICSBonds(m) + >>> res = find_brics_bonds(m) >>> res >>> res.next() ((3, 2), ('3', '4')) >>> m = Chem.MolFromSmiles('CC=CC') - >>> res = list(FindrBRICSBonds(m)) + >>> res = list(find_brics_bonds(m)) >>> sorted(res) [((1, 2), ('7', '7'))] make sure we don't match ring bonds: >>> m = Chem.MolFromSmiles('O=C1NCCC1') - >>> list(FindrBRICSBonds(m)) + >>> list(find_brics_bonds(m)) [] another nice one, make sure environment 8 doesn't match something connected @@ -431,87 +478,95 @@ def FindrBRICSBonds(mol, randomizeOrder=False, silent=True): """ letter = re.compile("[a-z,A-Z]") - indices = range(len(bondMatchers)) - bondsDone = set() + indices = list(range(len(BOND_MATCHERS))) + bonds_done = set() if randomizeOrder: random.shuffle(indices) - envMatches = {} - for env, patt in environMatchers.items(): # Leili - envMatches[env] = mol.HasSubstructMatch(patt) - for gpIdx in indices: + env_matches = {} + for env, substruct_mol in ENV_MATCHERS.items(): # Leili + env_matches[env] = mol.HasSubstructMatch(substruct_mol) + for group_idx in indices: if randomizeOrder: - compats = bondMatchers[gpIdx][:] - random.shuffle(compats) + matchers_list = BOND_MATCHERS[group_idx][:] + random.shuffle(matchers_list) else: - compats = bondMatchers[gpIdx] - for i1, i2, bType, patt in compats: - if not envMatches["L" + i1] or not envMatches["L" + i2]: + matchers_list = BOND_MATCHERS[group_idx] + for i1, i2, bond_type, substruct_mol in matchers_list: + if not env_matches["L" + i1] or not env_matches["L" + i2]: continue - matches = mol.GetSubstructMatches(patt) + matches = mol.GetSubstructMatches(substruct_mol) i1 = letter.sub("", i1) i2 = letter.sub("", i2) for match in matches: - if match not in bondsDone and (match[1], match[0]) not in bondsDone: - bondsDone.add(match) + if match not in bonds_done and (match[1], match[0]) not in bonds_done: + bonds_done.add(match) yield (((match[0], match[1]), (i1, i2))) # Leili -def FindreBRICSBonds(mol, randomizeOrder=False, silent=True): +def find_r_brics_bonds( + mol: Chem.Mol, randomizeOrder: bool = False, silent: bool = True +) -> Generator[tuple[tuple[int, int], tuple[EnvironmentLabel, EnvironmentLabel]], None, None]: letter = re.compile("[a-z,A-Z]") - indices = range(len(bondMatchers_r)) - bondsDone = set() + indices = list(range(len(BOND_MATCHERS_R))) + + bonds_done = set() if randomizeOrder: random.shuffle(indices) - envMatches = {} - for env, patt in environMatchers_r.items(): # Leili - envMatches[env] = mol.HasSubstructMatch(patt) - for gpIdx in indices: + env_matches = {} + for env, substruct_mol in ENV_MATCHERS.items(): # Leili + env_matches[env] = mol.HasSubstructMatch(substruct_mol) + for group_idx in indices: if randomizeOrder: - compats = bondMatchers_r[gpIdx][:] - random.shuffle(compats) + matchers_list = BOND_MATCHERS_R[group_idx][:] + random.shuffle(matchers_list) else: - compats = bondMatchers_r[gpIdx] - for i1, i2, bType, patt in compats: - if not envMatches["L" + i1] or not envMatches["L" + i2]: + matchers_list = BOND_MATCHERS_R[group_idx] + for i1, i2, bond_type, substruct_mol in matchers_list: + if not env_matches["L" + i1] or not env_matches["L" + i2]: continue - matches = mol.GetSubstructMatches(patt) + matches = mol.GetSubstructMatches(substruct_mol) i1 = letter.sub("", i1) i2 = letter.sub("", i2) for match in matches: - if match not in bondsDone and (match[1], match[0]) not in bondsDone: - bondsDone.add(match) + if match not in bonds_done and (match[1], match[0]) not in bonds_done: + bonds_done.add(match) yield (((match[0], match[1]), (i1, i2))) -def BreakrBRICSBonds(mol, bonds=None, sanitize=True, silent=True): +def break_r_brics_bonds( + mol: Chem.Mol, + bonds: list[tuple[tuple[int, int], tuple[EnvironmentLabel, EnvironmentLabel]]] | None = None, + sanitize: bool = True, + silent: bool = True, +) -> Chem.Mol: """breaks the BRICS bonds in a molecule and returns the results >>> from rdkit import Chem >>> m = Chem.MolFromSmiles('CCCOCC') - >>> m2=BreakrBRICSBonds(m) + >>> m2=break_r_brics_bonds(m) >>> Chem.MolToSmiles(m2,True) '[3*]O[3*].[4*]CC.[4*]CCC' a more complicated case: >>> m = Chem.MolFromSmiles('CCCOCCC(=O)c1ccccc1') - >>> m2=BreakrBRICSBonds(m) + >>> m2=break_r_brics_bonds(m) >>> Chem.MolToSmiles(m2,True) '[3*]O[3*].[4*]CCC.[4*]CCC([6*])=O.[16*]c1ccccc1' can also specify a limited set of bonds to work with: >>> m = Chem.MolFromSmiles('CCCOCC') - >>> m2 = BreakrBRICSBonds(m,[((3, 2), ('3', '4'))]) + >>> m2 = break_r_brics_bonds(m,[((3, 2), ('3', '4'))]) >>> Chem.MolToSmiles(m2,True) '[3*]OCC.[4*]CCC' this can be used as an alternate approach for doing a BRICS decomposition by - following BreakrBRICSBonds with a call to Chem.GetMolFrags: + following break_r_brics_bonds with a call to Chem.GetMolFrags: >>> m = Chem.MolFromSmiles('CCCOCC') - >>> m2=BreakrBRICSBonds(m) + >>> m2=break_r_brics_bonds(m) >>> frags = Chem.GetMolFrags(m2,asMols=True) >>> [Chem.MolToSmiles(x,True) for x in frags] ['[4*]CCC', '[3*]O[3*]', '[4*]CC'] @@ -563,25 +618,25 @@ def BreakrBRICSBonds(mol, bonds=None, sanitize=True, silent=True): return res -def rBRICSDecompose( - mol, - allNodes=None, - minFragmentSize=1, - onlyUseReactions=None, - silent=True, - keepNonLeafNodes=False, - singlePass=False, - returnMols=False, -): +def r_brics_decompose( + mol: Chem.Mol, + allNodes: set[str] | None = None, + minFragmentSize: int = 1, + onlyUseReactions: list[tuple[int, int]] | None = None, + silent: bool = True, + keepNonLeafNodes: bool = False, + singlePass: bool = False, + returnMols: bool = False, +) -> list[Chem.Mol]: """returns the BRICS decomposition for a molecule >>> from rdkit import Chem >>> m = Chem.MolFromSmiles('CCCOCc1cc(c2ncccc2)ccc1') - >>> res = list(rBRICSDecompose(m)) + >>> res = list(r_brics_decompose(m)) >>> sorted(res) ['[14*]c1ccccn1', '[16*]c1cccc([16*])c1', '[3*]O[3*]', '[4*]CCC', '[4*]C[8*]'] - >>> res = rBRICSDecompose(m,returnMols=True) + >>> res = r_brics_decompose(m,returnMols=True) >>> res[0] >>> smis = [Chem.MolToSmiles(x,True) for x in res] @@ -590,37 +645,37 @@ def rBRICSDecompose( nexavar, an example from the paper (corrected): >>> m = Chem.MolFromSmiles('CNC(=O)C1=NC=CC(OC2=CC=C(NC(=O)NC3=CC(=C(Cl)C=C3)C(F)(F)F)C=C2)=C1') - >>> res = list(rBRICSDecompose(m)) + >>> res = list(r_brics_decompose(m)) >>> sorted(res) ['[1*]C([1*])=O', '[1*]C([6*])=O', '[14*]c1cc([16*])ccn1', '[16*]c1ccc(Cl)c([16*])c1', '[16*]c1ccc([16*])cc1', '[3*]O[3*]', '[5*]NC', '[5*]N[5*]', '[8*]C(F)(F)F'] it's also possible to keep pieces that haven't been fully decomposed: >>> m = Chem.MolFromSmiles('CCCOCC') - >>> res = list(rBRICSDecompose(m,keepNonLeafNodes=True)) + >>> res = list(r_brics_decompose(m,keepNonLeafNodes=True)) >>> sorted(res) ['CCCOCC', '[3*]OCC', '[3*]OCCC', '[3*]O[3*]', '[4*]CC', '[4*]CCC'] >>> m = Chem.MolFromSmiles('CCCOCc1cc(c2ncccc2)ccc1') - >>> res = list(rBRICSDecompose(m,keepNonLeafNodes=True)) + >>> res = list(r_brics_decompose(m,keepNonLeafNodes=True)) >>> sorted(res) ['CCCOCc1cccc(-c2ccccn2)c1', '[14*]c1ccccn1', '[16*]c1cccc(-c2ccccn2)c1', '[16*]c1cccc(COCCC)c1', '[16*]c1cccc([16*])c1', '[3*]OCCC', '[3*]OC[8*]', '[3*]OCc1cccc(-c2ccccn2)c1', '[3*]OCc1cccc([16*])c1', '[3*]O[3*]', '[4*]CCC', '[4*]C[8*]', '[4*]Cc1cccc(-c2ccccn2)c1', '[4*]Cc1cccc([16*])c1', '[8*]COCCC'] or to only do a single pass of decomposition: >>> m = Chem.MolFromSmiles('CCCOCc1cc(c2ncccc2)ccc1') - >>> res = list(rBRICSDecompose(m,singlePass=True)) + >>> res = list(r_brics_decompose(m,singlePass=True)) >>> sorted(res) ['CCCOCc1cccc(-c2ccccn2)c1', '[14*]c1ccccn1', '[16*]c1cccc(-c2ccccn2)c1', '[16*]c1cccc(COCCC)c1', '[3*]OCCC', '[3*]OCc1cccc(-c2ccccn2)c1', '[4*]CCC', '[4*]Cc1cccc(-c2ccccn2)c1', '[8*]COCCC'] setting a minimum size for the fragments: >>> m = Chem.MolFromSmiles('CCCOCC') - >>> res = list(rBRICSDecompose(m,keepNonLeafNodes=True,minFragmentSize=2)) + >>> res = list(r_brics_decompose(m,keepNonLeafNodes=True,minFragmentSize=2)) >>> sorted(res) ['CCCOCC', '[3*]OCC', '[3*]OCCC', '[4*]CC', '[4*]CCC'] >>> m = Chem.MolFromSmiles('CCCOCC') - >>> res = list(rBRICSDecompose(m,keepNonLeafNodes=True,minFragmentSize=3)) + >>> res = list(r_brics_decompose(m,keepNonLeafNodes=True,minFragmentSize=3)) >>> sorted(res) ['CCCOCC', '[3*]OCC', '[4*]CCC'] - >>> res = list(rBRICSDecompose(m,minFragmentSize=2)) + >>> res = list(r_brics_decompose(m,minFragmentSize=2)) >>> sorted(res) ['[3*]OCC', '[3*]OCCC', '[4*]CC', '[4*]CCC'] @@ -633,13 +688,13 @@ def rBRICSDecompose( allNodes = set() if mSmi in allNodes: - return set() + return [] - activePool = {mSmi: mol} + activePool: dict[str, Chem.Mol] = {mSmi: mol} allNodes.add(mSmi) - foundMols = {mSmi: mol} + foundMols: dict[str, Chem.Mol] = {mSmi: mol} for gpIdx, reactionGp in enumerate(reactions): - newPool = {} + newPool: dict[str, Chem.Mol] = {} while activePool: matched = False nSmi = list(activePool.keys())[0] @@ -687,21 +742,27 @@ def rBRICSDecompose( activePool = newPool if not (singlePass or keepNonLeafNodes): if not returnMols: - res = set(activePool.keys()) + return list(activePool.keys()) else: - res = activePool.values() + return list(activePool.values()) else: if not returnMols: - res = allNodes + return list(allNodes) else: - res = foundMols.values() - return res + return list(foundMols.values()) dummyPattern = Chem.MolFromSmiles("[*]") -def BRICSBuild(fragments, onlyCompleteMols=True, seeds=None, uniquify=True, scrambleReagents=True, maxDepth=3): +def BRICSBuild( + fragments: list[Chem.Mol], + onlyCompleteMols: bool = True, + seeds: list[Chem.Mol] | None = None, + uniquify: bool = True, + scrambleReagents: bool = True, + maxDepth: int = 3, +) -> Generator[Chem.Mol, None, None]: seen = set() if not seeds: seeds = list(fragments) @@ -709,10 +770,10 @@ def BRICSBuild(fragments, onlyCompleteMols=True, seeds=None, uniquify=True, scra seeds = list(seeds) random.shuffle(seeds) if scrambleReagents: - tempReactions = list(reverseReactions) + tempReactions = list(REVERSE_REACTIONS) random.shuffle(tempReactions) else: - tempReactions = reverseReactions + tempReactions = REVERSE_REACTIONS for seed in seeds: seedIsR1 = False seedIsR2 = False @@ -761,33 +822,33 @@ def BRICSBuild(fragments, onlyCompleteMols=True, seeds=None, uniquify=True, scra # Leili # Iteratively breaks all aliphatic chains using linkage L20-L21, just in case chain is too long and L20-L23 aren't enough # Not the most efficient code yet -def reBRICS(fragments): +def reBRICS(fragments: list[Chem.Mol]) -> list[Chem.Mol]: oldfragments = fragments breakable = [1] * len(oldfragments) breakout = sum(breakable) iteri = 0 while breakout > 0: iii = 0 - newfrags = () - newbreakable = [] + newfrags: list[Chem.Mol] = [] + newbreakable: list[int] = [] for frag in oldfragments: heavy = frag.GetNumHeavyAtoms() if heavy > 5: if len(frag.GetSubstructMatch(Chem.MolFromSmiles("CCCCCC"))) > 0: - secondbonds = FindreBRICSBonds(frag) # only breaks aliphatic chains - secondpieces = BreakrBRICSBonds(frag, secondbonds) + secondbonds = list(find_r_brics_bonds(frag)) # only breaks aliphatic chains + secondpieces = break_r_brics_bonds(frag, secondbonds) secondfrags = Chem.GetMolFrags(secondpieces, asMols=True) if len(secondfrags) > 1: newfrags = newfrags + secondfrags newbreakable = newbreakable + [1] * len(secondfrags) else: newfrags = newfrags + secondfrags - newbreakable = newbreakable.append(0) # 1 frag->1 frag, no longer breakable, criteria #1 + newbreakable.append(0) # 1 frag->1 frag, no longer breakable, criteria #1 else: - newfrags = newfrags + (frag,) + newfrags.append(frag) newbreakable.append(0) # frag doesn't contain CCCCCC chain, no longer breakable, criteria #2 else: - newfrags = newfrags + (frag,) + newfrags.append(frag) newbreakable.append(0) # frag contains less than 5 heavy atoms, no longer breakable, criteria #3 iii += 1 oldfragments = newfrags diff --git a/src/fragmentretro/fragmenter.py b/src/fragmentretro/fragmenter.py index 68cd746..31a4f3b 100644 --- a/src/fragmentretro/fragmenter.py +++ b/src/fragmentretro/fragmenter.py @@ -1,11 +1,11 @@ """Module for fragmenting molecules using BRICS (add other algorithms later).""" -from fragmentation.rBRICS import BreakrBRICSBonds, FindrBRICSBonds from rdkit.Chem import Mol from rdkit.Chem.BRICS import BreakBRICSBonds, FindBRICSBonds -from FragmentRetro.fragmenter_base import Fragmenter -from FragmentRetro.utils.type_definitions import BondType +from fragmentretro.fragmentation.r_brics import break_r_brics_bonds, find_brics_bonds +from fragmentretro.fragmenter_base import Fragmenter +from fragmentretro.utils.type_definitions import BondType class BRICSFragmenter(Fragmenter): @@ -36,7 +36,7 @@ def __init__(self, smiles: str) -> None: super().__init__(smiles) def _find_fragmentation_bonds(self, mol: Mol) -> list[BondType]: - return list(FindrBRICSBonds(mol)) # type: ignore[no-untyped-call] + return list(find_brics_bonds(mol)) # type: ignore[no-untyped-call] def _break_bonds(self, mol: Mol, bonds: list[BondType]) -> Mol: - return BreakrBRICSBonds(mol, bonds) # type: ignore[no-untyped-call] + return break_r_brics_bonds(mol, bonds) # type: ignore[no-untyped-call] From af2123fa2ec4c6e3c7053dfc1e36d87d933ac831 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:16:24 -0400 Subject: [PATCH 04/24] STYLE: enable sim lint rules --- .pre-commit-config.yaml | 13 +++--------- data/process_buyables.py | 11 +++++----- pyproject.toml | 18 ++++++++-------- scripts/paroutes_example.py | 3 +-- src/fragmentretro/app/gui/controller.py | 14 ++++++------- src/fragmentretro/app/gui/state.py | 3 +-- src/fragmentretro/fragmentation/r_brics.py | 12 ++++------- src/fragmentretro/fragmenter_base.py | 24 ++++++++++------------ src/fragmentretro/retrosynthesis.py | 5 +---- src/fragmentretro/solutions.py | 7 +++---- src/fragmentretro/substructure_matcher.py | 5 ++--- src/fragmentretro/utils/filter_compound.py | 7 +++---- 12 files changed, 50 insertions(+), 72 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 63daf63..a62665c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,23 +6,16 @@ repos: hooks: - id: ruff name: ruff (linter) - entry: ruff check - language: system + entry: ruff check --fix + language: python types: [python] - id: ruff-format name: ruff (formatter) entry: ruff format - language: system + language: python types: [python] - - id: isort - name: isort - entry: isort - language: system - types: [python] - args: [--profile=black] - # - id: mypy # name: mypy # entry: mypy diff --git a/data/process_buyables.py b/data/process_buyables.py index 55cd6af..f0d6641 100644 --- a/data/process_buyables.py +++ b/data/process_buyables.py @@ -3,11 +3,10 @@ import shutil from pathlib import Path -from tqdm import tqdm - from FragmentRetro.utils.filter_compound import precompute_properties from FragmentRetro.utils.helpers import canonicalize_smiles from FragmentRetro.utils.logging_config import logger +from tqdm import tqdm DATA_PATH = Path(__file__).parent BUYABLES_PATH = DATA_PATH / "buyables" @@ -15,9 +14,11 @@ if __name__ == "__main__": logger.info("Decompressing buyables data...") - with gzip.open(BUYABLES_PATH / "buyables_all.json.gz", "rb") as f_in: - with open(BUYABLES_PATH / "buyables_all.json", "wb") as f_out: - shutil.copyfileobj(f_in, f_out) + with ( + gzip.open(BUYABLES_PATH / "buyables_all.json.gz", "rb") as f_in, + open(BUYABLES_PATH / "buyables_all.json", "wb") as f_out, + ): + shutil.copyfileobj(f_in, f_out) logger.info("Loading buyables data...") with open(BUYABLES_PATH / "buyables_all.json", "r") as f: buyables = json.load(f) diff --git a/pyproject.toml b/pyproject.toml index 99a0569..35c6669 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,16 +55,16 @@ ignore_errors = true [tool.ruff] line-length = 120 -# lint.select = [ +lint.select = [ # "E", # pycodestyle # "F", # Pyflakes # "UP", # pyupgrade # "B", # flake8-bugbear -# "SIM", # flake8-simplify -# "I", # isort -# ] -# lint.ignore = [ -# "E501", # o respect fmt off blocks -# "SIM108", # disagree w/ https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp/ -# ] -# exclude = ["tests"] \ No newline at end of file + "SIM", # flake8-simplify + "I", # isort +] +lint.ignore = [ + "E501", # o respect fmt off blocks + "SIM108", # disagree w/ https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp/ +] +exclude = ["tests"] \ No newline at end of file diff --git a/scripts/paroutes_example.py b/scripts/paroutes_example.py index 8d6a053..f463f86 100644 --- a/scripts/paroutes_example.py +++ b/scripts/paroutes_example.py @@ -1,12 +1,11 @@ import pickle from pathlib import Path -from tqdm import tqdm - from FragmentRetro.fragmenter import BRICSFragmenter # or use rBRICSFragmenter from FragmentRetro.retrosynthesis import Retrosynthesis from FragmentRetro.solutions import RetrosynthesisSolution from FragmentRetro.utils.logging_config import logger +from tqdm import tqdm DATA_PATH = Path(__name__).parent / "data" PAROUTES_PATH = DATA_PATH / "paroutes" diff --git a/src/fragmentretro/app/gui/controller.py b/src/fragmentretro/app/gui/controller.py index 4e265f6..c3127ee 100644 --- a/src/fragmentretro/app/gui/controller.py +++ b/src/fragmentretro/app/gui/controller.py @@ -1,3 +1,4 @@ +import contextlib import io from pathlib import Path from typing import cast @@ -27,17 +28,16 @@ target_smiles_input, ) from app.logging_config import logger -from IPython.display import display -from PIL.Image import Image as PILImage -from rdkit import Chem -from rdkit.Chem import Draw - from FragmentRetro.fragmenter import BRICSFragmenter, rBRICSFragmenter from FragmentRetro.fragmenter_base import Fragmenter from FragmentRetro.retrosynthesis import Retrosynthesis from FragmentRetro.solutions import RetrosynthesisSolution from FragmentRetro.utils.helpers import sort_by_heavy_atoms from FragmentRetro.utils.type_definitions import CombType, SolutionType +from IPython.display import display +from PIL.Image import Image as PILImage +from rdkit import Chem +from rdkit.Chem import Draw class GuiController: @@ -179,10 +179,8 @@ def run_retrosynthesis_on_click(self, b: widgets.Button) -> None: def update_fragment_comb_dropdown(self, solution: SolutionType | None) -> None: """Populates the fragment comb dropdown based on a single solution.""" - try: + with contextlib.suppress(ValueError): self.fragment_comb_dropdown.unobserve(self.on_fragment_comb_select, names="value") - except ValueError: - pass if solution: self.fragment_comb_dropdown.options = [(str(comb), comb) for comb in solution] diff --git a/src/fragmentretro/app/gui/state.py b/src/fragmentretro/app/gui/state.py index 2b9f168..0b025f1 100644 --- a/src/fragmentretro/app/gui/state.py +++ b/src/fragmentretro/app/gui/state.py @@ -1,8 +1,7 @@ -from PIL.Image import Image as PILImage # For type hinting - from FragmentRetro.retrosynthesis import Retrosynthesis from FragmentRetro.solutions import RetrosynthesisSolution from FragmentRetro.utils.type_definitions import CombType, SolutionType +from PIL.Image import Image as PILImage # For type hinting class AppState: diff --git a/src/fragmentretro/fragmentation/r_brics.py b/src/fragmentretro/fragmentation/r_brics.py index 619d928..bbab472 100644 --- a/src/fragmentretro/fragmentation/r_brics.py +++ b/src/fragmentretro/fragmentation/r_brics.py @@ -785,12 +785,10 @@ def BRICSBuild( seedIsR2 = True for fragment in fragments: ps = None - if fragment.HasSubstructMatch(rxn._matchers[0]): - if seedIsR2: - ps = rxn.RunReactants((fragment, seed)) - if fragment.HasSubstructMatch(rxn._matchers[1]): - if seedIsR1: - ps = rxn.RunReactants((seed, fragment)) + if fragment.HasSubstructMatch(rxn._matchers[0]) and seedIsR2: + ps = rxn.RunReactants((fragment, seed)) + if fragment.HasSubstructMatch(rxn._matchers[1]) and seedIsR1: + ps = rxn.RunReactants((seed, fragment)) if ps: for p in ps: if uniquify: @@ -828,7 +826,6 @@ def reBRICS(fragments: list[Chem.Mol]) -> list[Chem.Mol]: breakout = sum(breakable) iteri = 0 while breakout > 0: - iii = 0 newfrags: list[Chem.Mol] = [] newbreakable: list[int] = [] for frag in oldfragments: @@ -850,7 +847,6 @@ def reBRICS(fragments: list[Chem.Mol]) -> list[Chem.Mol]: else: newfrags.append(frag) newbreakable.append(0) # frag contains less than 5 heavy atoms, no longer breakable, criteria #3 - iii += 1 oldfragments = newfrags breakable = newbreakable breakout = sum(newbreakable) diff --git a/src/fragmentretro/fragmenter_base.py b/src/fragmentretro/fragmenter_base.py index 3c53462..b0c0751 100644 --- a/src/fragmentretro/fragmenter_base.py +++ b/src/fragmentretro/fragmenter_base.py @@ -4,11 +4,10 @@ import matplotlib.pyplot as plt import networkx as nx -from rdkit import Chem -from rdkit.Chem import Mol - from FragmentRetro.utils.logging_config import logger from FragmentRetro.utils.type_definitions import AtomMappingType, BondType, CombType +from rdkit import Chem +from rdkit.Chem import Mol class Fragmenter(ABC): @@ -58,16 +57,15 @@ def _build_fragment_graph(self) -> nx.Graph: frag1 = atom_to_frag.get(atom1) frag2 = atom_to_frag.get(atom2) - if frag1 != frag2 and frag1 is not None and frag2 is not None: - if not G.has_edge(frag1, frag2): - G.add_edge( - frag1, - frag2, - bond_type=(type1, type2), - atoms=(atom1, atom2), - edge_index=edge_index, - ) - edge_index += 1 + if (frag1 != frag2) and (frag1 is not None) and (frag2 is not None) and not G.has_edge(frag1, frag2): + G.add_edge( + frag1, + frag2, + bond_type=(type1, type2), + atoms=(atom1, atom2), + edge_index=edge_index, + ) + edge_index += 1 return G diff --git a/src/fragmentretro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py index 33ee49e..10cea43 100644 --- a/src/fragmentretro/retrosynthesis.py +++ b/src/fragmentretro/retrosynthesis.py @@ -72,10 +72,7 @@ def _check_effective_comb(self, comb: CombType) -> bool: """ len_comb = len(comb) len_minus_one_invalid_combs = self.invalid_combinations_dict.get(len_comb - 1, []) - for invalid_comb in len_minus_one_invalid_combs: - if set(invalid_comb).issubset(set(comb)): - return False - return True + return all(not set(invalid_comb).issubset(set(comb)) for invalid_comb in len_minus_one_invalid_combs) def _get_prefiltered_indices(self, comb: CombType) -> Optional[FilterIndicesType]: """Get prefiltered indices for a given combination. diff --git a/src/fragmentretro/solutions.py b/src/fragmentretro/solutions.py index eda0764..63775fc 100644 --- a/src/fragmentretro/solutions.py +++ b/src/fragmentretro/solutions.py @@ -1,13 +1,12 @@ from itertools import chain from typing import Optional -from PIL import Image -from rdkit import Chem -from rdkit.Chem import Draw - from FragmentRetro.retrosynthesis import Retrosynthesis from FragmentRetro.utils.logging_config import logger from FragmentRetro.utils.type_definitions import CombType, SolutionType +from PIL import Image +from rdkit import Chem +from rdkit.Chem import Draw class RetrosynthesisSolution: diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index 1064995..ca6757c 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -2,11 +2,10 @@ from multiprocessing import Pool, cpu_count from typing import Optional, cast -from rdkit import Chem -from rdkit.Chem.rdchem import Atom - from FragmentRetro.utils.logging_config import logger from FragmentRetro.utils.type_definitions import BBsType +from rdkit import Chem +from rdkit.Chem.rdchem import Atom class SubstructureMatcher: diff --git a/src/fragmentretro/utils/filter_compound.py b/src/fragmentretro/utils/filter_compound.py index 1883cd3..64713d9 100644 --- a/src/fragmentretro/utils/filter_compound.py +++ b/src/fragmentretro/utils/filter_compound.py @@ -3,10 +3,6 @@ from typing import Optional import numpy as np -from rdkit import Chem -from rdkit.Chem import rdMolDescriptors -from tqdm import tqdm - from FragmentRetro.utils.helpers import canonicalize_smiles, replace_dummy_atoms_regex from FragmentRetro.utils.logging_config import logger from FragmentRetro.utils.type_definitions import ( @@ -14,6 +10,9 @@ FilterIndicesType, MolProperties, ) +from rdkit import Chem +from rdkit.Chem import rdMolDescriptors +from tqdm import tqdm def get_mol_properties(smiles: str, fpSize: int = 2048) -> MolProperties: From 70eabdf0fe374c703b8282860c5123b83b90827a Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:24:05 -0400 Subject: [PATCH 05/24] STYLE: enable bugbear --- pyproject.toml | 2 +- src/fragmentretro/fragmentation/r_brics.py | 14 +++++++------- src/fragmentretro/solutions.py | 2 +- src/fragmentretro/substructure_matcher.py | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 35c6669..36a5619 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ lint.select = [ # "E", # pycodestyle # "F", # Pyflakes # "UP", # pyupgrade -# "B", # flake8-bugbear + "B", # flake8-bugbear "SIM", # flake8-simplify "I", # isort ] diff --git a/src/fragmentretro/fragmentation/r_brics.py b/src/fragmentretro/fragmentation/r_brics.py index bbab472..0378728 100644 --- a/src/fragmentretro/fragmentation/r_brics.py +++ b/src/fragmentretro/fragmentation/r_brics.py @@ -360,7 +360,7 @@ def initialize_bond_matchers( environments: EnvironmentSmartsMap, reaction_definitions: BondCleavageDefinitions ) -> BondMatcherList: bond_matchers = [] - for group_idx, rule_group in enumerate(reaction_definitions): + for rule_group in reaction_definitions: tmp = [] for env_idx1, env_idx2, bond in rule_group: smarts1 = environments["L%s" % env_idx1] @@ -382,7 +382,7 @@ def init_reactions( rule_groups = copy.deepcopy(reaction_definitions) smarts_groups = [] for rule_group in rule_groups: - for rule_idx, rule in enumerate(rule_group): + for rule in rule_group: env_idx1, env_idx2, bond = rule smarts1 = environs["L" + env_idx1] smarts2 = environs["L" + env_idx2] @@ -407,8 +407,8 @@ def init_reactions( reactions = tuple([[Reactions.ReactionFromSmarts(y) for y in x] for x in smarts_groups]) reverse_reactions = [] - for group_idx, smarts_group in enumerate(smarts_groups): - for smarts_idx, smarts in enumerate(smarts_group): + for smarts_group in smarts_groups: + for smarts in smarts_group: reactants, products = smarts.split(">>") smarts = "%s>>%s" % (products, reactants) rxn = Reactions.ReactionFromSmarts(smarts) @@ -492,7 +492,7 @@ def find_brics_bonds( random.shuffle(matchers_list) else: matchers_list = BOND_MATCHERS[group_idx] - for i1, i2, bond_type, substruct_mol in matchers_list: + for i1, i2, _, substruct_mol in matchers_list: if not env_matches["L" + i1] or not env_matches["L" + i2]: continue matches = mol.GetSubstructMatches(substruct_mol) @@ -524,7 +524,7 @@ def find_r_brics_bonds( random.shuffle(matchers_list) else: matchers_list = BOND_MATCHERS_R[group_idx] - for i1, i2, bond_type, substruct_mol in matchers_list: + for i1, i2, _, substruct_mol in matchers_list: if not env_matches["L" + i1] or not env_matches["L" + i2]: continue matches = mol.GetSubstructMatches(substruct_mol) @@ -729,7 +729,7 @@ def r_brics_decompose( prod.pSmi = pSmi if seqOk: matched = True - for nats, prod in prodSeq: + for _, prod in prodSeq: pSmi = prod.pSmi # print '\t',nats,pSmi if pSmi not in allNodes: diff --git a/src/fragmentretro/solutions.py b/src/fragmentretro/solutions.py index 63775fc..e8c3e90 100644 --- a/src/fragmentretro/solutions.py +++ b/src/fragmentretro/solutions.py @@ -143,7 +143,7 @@ def visualize_solutions( # Convert SMILES to RDKit molecules mols = [Chem.MolFromSmiles(smiles) for smiles in all_smiles] # Draw molecules in a grid - legends = [f"{comb}: {smiles}" for comb, smiles in zip(solution, all_smiles)] + legends = [f"{comb}: {smiles}" for comb, smiles in zip(solution, all_smiles, strict=False)] img = Draw.MolsToGridImage(mols, molsPerRow=molsPerRow, subImgSize=subImgSize, legends=legends) all_img.append(img) return all_img diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index ca6757c..7acd6eb 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -11,7 +11,7 @@ class SubstructureMatcher: def __init__( self, - BBs: BBsType = set(), + BBs: BBsType, useChirality: bool = True, parallelize: bool = False, num_cores: Optional[int] = None, @@ -181,7 +181,7 @@ def get_substructure_BBs(self, fragment: str) -> BBsType: results = pool.starmap( self.is_strict_substructure, [(fragment, bb, self.useChirality) for bb in self.BBs] ) - strict_substructure_BBs = set(bb for bb, result in zip(self.BBs, results) if result) + strict_substructure_BBs = set(bb for bb, result in zip(self.BBs, results, strict=False) if result) else: # Fallback to single-threaded execution From b8b0a2113e7555d0ed83cc5e77e100926efcf64f Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:28:17 -0400 Subject: [PATCH 06/24] STYLE: enable pyupgrade --- data/process_buyables.py | 2 +- data/process_stock.py | 4 ++-- pyproject.toml | 2 +- scripts/paroutes_example.py | 2 +- src/fragmentretro/fragmentation/r_brics.py | 21 ++++++++++-------- src/fragmentretro/retrosynthesis.py | 10 ++++----- src/fragmentretro/solutions.py | 4 ++-- src/fragmentretro/substructure_matcher.py | 2 +- src/fragmentretro/utils/filter_compound.py | 8 +++---- src/fragmentretro/utils/type_definitions.py | 24 ++++++++++----------- 10 files changed, 39 insertions(+), 40 deletions(-) diff --git a/data/process_buyables.py b/data/process_buyables.py index f0d6641..e0a3837 100644 --- a/data/process_buyables.py +++ b/data/process_buyables.py @@ -20,7 +20,7 @@ ): shutil.copyfileobj(f_in, f_out) logger.info("Loading buyables data...") - with open(BUYABLES_PATH / "buyables_all.json", "r") as f: + with open(BUYABLES_PATH / "buyables_all.json") as f: buyables = json.load(f) buyables_smiles = [buyable["smiles"] for buyable in buyables] diff --git a/data/process_stock.py b/data/process_stock.py index 7982e80..3c35d6e 100644 --- a/data/process_stock.py +++ b/data/process_stock.py @@ -8,13 +8,13 @@ if __name__ == "__main__": - with open(PAROUTES_PATH / "n1-stock.txt", "r") as f: + with open(PAROUTES_PATH / "n1-stock.txt") as f: n1_stock = [line.strip() for line in f.readlines()] PRECOMPUTE_PATH.mkdir(parents=True, exist_ok=True) precompute_properties(n1_stock, PRECOMPUTE_PATH / "n1_stock_properties.json") # precompute_properties(n1_stock, PRECOMPUTE_PATH / "n1_stock_properties_fp1024.json", fpSize=1024) - with open(PAROUTES_PATH / "n5-stock.txt", "r") as f: + with open(PAROUTES_PATH / "n5-stock.txt") as f: n5_stock = [line.strip() for line in f.readlines()] PRECOMPUTE_PATH.mkdir(parents=True, exist_ok=True) precompute_properties(n5_stock, PRECOMPUTE_PATH / "n5_stock_properties.json") diff --git a/pyproject.toml b/pyproject.toml index 36a5619..5f85b3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,7 @@ line-length = 120 lint.select = [ # "E", # pycodestyle # "F", # Pyflakes -# "UP", # pyupgrade + "UP", # pyupgrade "B", # flake8-bugbear "SIM", # flake8-simplify "I", # isort diff --git a/scripts/paroutes_example.py b/scripts/paroutes_example.py index f463f86..accab59 100644 --- a/scripts/paroutes_example.py +++ b/scripts/paroutes_example.py @@ -14,7 +14,7 @@ ####### Change this -with open(PAROUTES_PATH / "n1-stock.txt", "r") as f: +with open(PAROUTES_PATH / "n1-stock.txt") as f: n1_stock = [line.strip() for line in f.readlines()] with open(PAROUTES_PATH / "n1-targets.txt", "rb") as f: diff --git a/src/fragmentretro/fragmentation/r_brics.py b/src/fragmentretro/fragmentation/r_brics.py index 0378728..e553f62 100644 --- a/src/fragmentretro/fragmentation/r_brics.py +++ b/src/fragmentretro/fragmentation/r_brics.py @@ -45,7 +45,7 @@ import copy import random import re -from typing import Generator +from collections.abc import Generator from rdkit import Chem from rdkit.Chem import rdChemReactions as Reactions @@ -363,12 +363,13 @@ def initialize_bond_matchers( for rule_group in reaction_definitions: tmp = [] for env_idx1, env_idx2, bond in rule_group: - smarts1 = environments["L%s" % env_idx1] - smarts2 = environments["L%s" % env_idx2] + smarts1 = environments[f"L{env_idx1}"] + smarts2 = environments[f"L{env_idx2}"] if "@" in bond: # Leili - patt = "[$(%s)]%s[$(%s)]" % (smarts1, bond, smarts2) + patt = f"[$({smarts1})]{bond}[$({smarts2})]" else: - patt = "[$(%s)]%s;!@[$(%s)]" % (smarts1, bond, smarts2) + # patt = "[$(%s)]%s;!@[$(%s)]" % (smarts1, bond, smarts2) + patt = f"[$({smarts1})]{bond};!@[$({smarts2})]" # patt = '[$(%s)]%s;!@[$(%s)]'%(e1,bType,e2) #original patt = Chem.MolFromSmarts(patt) tmp.append((env_idx1, env_idx2, bond, patt)) @@ -390,9 +391,11 @@ def init_reactions( g2 = re.sub("[a-z,A-Z]", "", env_idx2) if "@" not in bond: # Leili # if 1 == 1: - sma = "[$(%s):1]%s;!@[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (smarts1, bond, smarts2, g1, g2) + # sma = "[$(%s):1]%s;!@[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (smarts1, bond, smarts2, g1, g2) + sma = f"[$({smarts1})]{bond};!@[$({smarts2})]>>[{g1}*]-[*:1].[{g2}*]-[*:2]" else: - sma = "[$(%s):1]%s[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (smarts1, bond, smarts2, g1, g2) + # sma = "[$(%s):1]%s[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (smarts1, bond, smarts2, g1, g2) + sma = f"[$({smarts1})]{bond}[$({smarts2})]>>[{g1}*]-[*:1].[{g2}*]-[*:2]" smarts_groups.append(sma) # sma='[$(%s):1]%s;!@[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]'%(r1,bnd,r2,g1,g2) #original # gp[j] =sma @@ -410,10 +413,10 @@ def init_reactions( for smarts_group in smarts_groups: for smarts in smarts_group: reactants, products = smarts.split(">>") - smarts = "%s>>%s" % (products, reactants) + smarts = f"{products}>>{reactants}" rxn = Reactions.ReactionFromSmarts(smarts) labels = re.findall(r"\[([0-9]+?)\*\]", products) - rxn._matchers = [Chem.MolFromSmiles("[%s*]" % x) for x in labels] + rxn._matchers = [Chem.MolFromSmiles(f"[{x}*]") for x in labels] reverse_reactions.append(rxn) return smarts_groups, reactions, reverse_reactions diff --git a/src/fragmentretro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py index 10cea43..5b70ee4 100644 --- a/src/fragmentretro/retrosynthesis.py +++ b/src/fragmentretro/retrosynthesis.py @@ -21,13 +21,13 @@ class Retrosynthesis: def __init__( self, fragmenter: Fragmenter, - original_BBs: Optional[BBsType] = None, - mol_properties_path: Optional[Path] = None, + original_BBs: BBsType | None = None, + mol_properties_path: Path | None = None, fpSize: int = 2048, parallelize: bool = False, - num_cores: Optional[int] = None, + num_cores: int | None = None, core_factor: int = 10, - compound_filter: Optional[CompoundFilter] = None, + compound_filter: CompoundFilter | None = None, ): self.fragmenter = fragmenter self.num_fragments = fragmenter.num_fragments @@ -74,7 +74,7 @@ def _check_effective_comb(self, comb: CombType) -> bool: len_minus_one_invalid_combs = self.invalid_combinations_dict.get(len_comb - 1, []) return all(not set(invalid_comb).issubset(set(comb)) for invalid_comb in len_minus_one_invalid_combs) - def _get_prefiltered_indices(self, comb: CombType) -> Optional[FilterIndicesType]: + def _get_prefiltered_indices(self, comb: CombType) -> FilterIndicesType | None: """Get prefiltered indices for a given combination. This method retrieves a list of prefiltered indices based on valid diff --git a/src/fragmentretro/solutions.py b/src/fragmentretro/solutions.py index e8c3e90..b3ce4c8 100644 --- a/src/fragmentretro/solutions.py +++ b/src/fragmentretro/solutions.py @@ -55,7 +55,7 @@ def _find_complementary_combinations( @staticmethod def get_solutions( - valid_combinations: list[CombType], num_fragments: int, solution_cap: Optional[int] = None + valid_combinations: list[CombType], num_fragments: int, solution_cap: int | None = None ) -> list[SolutionType]: """ Generates all possible retrosynthesis solutions from a list of valid fragment combinations. @@ -95,7 +95,7 @@ def get_solutions( return all_solutions - def fill_solutions(self, solution_cap: Optional[int] = None) -> None: + def fill_solutions(self, solution_cap: int | None = None) -> None: """Fill the solutions list with all possible solutions.""" self.solutions = self.get_solutions(self.valid_combinations, self.num_fragments, solution_cap) diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index 7acd6eb..9078b13 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -14,7 +14,7 @@ def __init__( BBs: BBsType, useChirality: bool = True, parallelize: bool = False, - num_cores: Optional[int] = None, + num_cores: int | None = None, core_factor: int = 10, ): """ diff --git a/src/fragmentretro/utils/filter_compound.py b/src/fragmentretro/utils/filter_compound.py index 64713d9..cd73de8 100644 --- a/src/fragmentretro/utils/filter_compound.py +++ b/src/fragmentretro/utils/filter_compound.py @@ -96,7 +96,7 @@ def _load_mol_properties(self) -> None: """Loads molecular properties from the JSON file.""" logger.info("[CompoundFilter] Loading mol properties") - with open(self.mol_properties_path, "r") as f: + with open(self.mol_properties_path) as f: mol_properties_list = json.load(f) self.len_BBs = len(mol_properties_list) @@ -118,9 +118,7 @@ def _create_numpy_arrays(self) -> None: for i, pfp in enumerate(self.pfp_list): self.pfp_bit_array[i, pfp] = True - def filter_compounds( - self, smiles: str, prefiltered_indices: Optional[FilterIndicesType] = None - ) -> FilterIndicesType: + def filter_compounds(self, smiles: str, prefiltered_indices: FilterIndicesType | None = None) -> FilterIndicesType: """Filters compounds based on a query SMILES string and prefiltered indices. Note that dummy atoms have to be replaced by hydrogen atoms so that we can get the minimal format for pattern fingerprint processing. @@ -176,7 +174,7 @@ def filter_compounds( return filtered_indices def get_filtered_BBs( - self, smiles: str, prefiltered_indices: Optional[FilterIndicesType] = None + self, smiles: str, prefiltered_indices: FilterIndicesType | None = None ) -> tuple[FilterIndicesType, BBsType]: """Filters building blocks based on a query SMILES string and prefiltered indices. diff --git a/src/fragmentretro/utils/type_definitions.py b/src/fragmentretro/utils/type_definitions.py index 312c614..1653036 100644 --- a/src/fragmentretro/utils/type_definitions.py +++ b/src/fragmentretro/utils/type_definitions.py @@ -1,42 +1,40 @@ """Type definitions for FragmentRetro package.""" -from typing import TypedDict - -from typing_extensions import TypeAlias +from typing import TypeAlias, TypedDict # Bond type (from BRICS): ((atom1_idx, atom2_idx), (type1, type2)) # Example: ((3, 2), ('3', '4')) -BondType: TypeAlias = tuple[tuple[int, int], tuple[str, str]] +type BondType = tuple[tuple[int, int], tuple[str, str]] # Atom mapping type: tuple of atom indices # Example: (0, 1, 2, 7) -AtomMappingType: TypeAlias = tuple[int, ...] +type AtomMappingType = tuple[int, ...] # Combination type: tuple of fragment indices (needs to be a tuple for hashing) -CombType: TypeAlias = tuple[int] +type CombType = tuple[int] # Solution type: list of combination types -SolutionType: TypeAlias = list[CombType] +type SolutionType = list[CombType] # Building block type: set of strings (SMILES) -BBsType: TypeAlias = set[str] +type BBsType = set[str] # Store the combinations for each stage # Example: {1: [(0, 1), (2, 3)]} ({stage number: list[CombType]}) # This can hold all combinations or effective combinations -StageCombDictType: TypeAlias = dict[int, list[CombType]] +type StageCombDictType = dict[int, list[CombType]] # Store the building blocks for each combination -CombBBsDictType: TypeAlias = dict[CombType, BBsType] +type CombBBsDictType = dict[CombType, BBsType] # Store the combination indices and building blocks for each fragment SMILES (can have dummy atoms) -FragmentBBsDictType: TypeAlias = dict[str, tuple[CombType, BBsType]] +type FragmentBBsDictType = dict[str, tuple[CombType, BBsType]] # Store the filtered indices -FilterIndicesType: TypeAlias = list[int] +type FilterIndicesType = list[int] # Store the filtered indices (from CompoundFilter) for each combination -CombFilterIndicesDictType: TypeAlias = dict[CombType, FilterIndicesType] +type CombFilterIndicesDictType = dict[CombType, FilterIndicesType] class MolProperties(TypedDict, total=True): From bf2f8a282ec759d9f0592f2dcfa13834d4a55d19 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:28:32 -0400 Subject: [PATCH 07/24] STYLE: enable pyflakes --- pyproject.toml | 2 +- src/fragmentretro/retrosynthesis.py | 2 +- src/fragmentretro/solutions.py | 1 - src/fragmentretro/substructure_matcher.py | 2 +- src/fragmentretro/utils/filter_compound.py | 1 - src/fragmentretro/utils/type_definitions.py | 2 +- 6 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5f85b3b..3a0b628 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ ignore_errors = true line-length = 120 lint.select = [ # "E", # pycodestyle -# "F", # Pyflakes + "F", # Pyflakes "UP", # pyupgrade "B", # flake8-bugbear "SIM", # flake8-simplify diff --git a/src/fragmentretro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py index 5b70ee4..496d1b6 100644 --- a/src/fragmentretro/retrosynthesis.py +++ b/src/fragmentretro/retrosynthesis.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Optional, cast +from typing import cast from FragmentRetro.fragmenter_base import Fragmenter from FragmentRetro.substructure_matcher import SubstructureMatcher diff --git a/src/fragmentretro/solutions.py b/src/fragmentretro/solutions.py index b3ce4c8..848211a 100644 --- a/src/fragmentretro/solutions.py +++ b/src/fragmentretro/solutions.py @@ -1,5 +1,4 @@ from itertools import chain -from typing import Optional from FragmentRetro.retrosynthesis import Retrosynthesis from FragmentRetro.utils.logging_config import logger diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index 9078b13..f1371c8 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -1,6 +1,6 @@ import re from multiprocessing import Pool, cpu_count -from typing import Optional, cast +from typing import cast from FragmentRetro.utils.logging_config import logger from FragmentRetro.utils.type_definitions import BBsType diff --git a/src/fragmentretro/utils/filter_compound.py b/src/fragmentretro/utils/filter_compound.py index cd73de8..b0ee2c5 100644 --- a/src/fragmentretro/utils/filter_compound.py +++ b/src/fragmentretro/utils/filter_compound.py @@ -1,6 +1,5 @@ import json from pathlib import Path -from typing import Optional import numpy as np from FragmentRetro.utils.helpers import canonicalize_smiles, replace_dummy_atoms_regex diff --git a/src/fragmentretro/utils/type_definitions.py b/src/fragmentretro/utils/type_definitions.py index 1653036..3035a1b 100644 --- a/src/fragmentretro/utils/type_definitions.py +++ b/src/fragmentretro/utils/type_definitions.py @@ -1,6 +1,6 @@ """Type definitions for FragmentRetro package.""" -from typing import TypeAlias, TypedDict +from typing import TypedDict # Bond type (from BRICS): ((atom1_idx, atom2_idx), (type1, type2)) # Example: ((3, 2), ('3', '4')) From d5c70aed066a023c914309b28c49d02bdf3f31ed Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:28:49 -0400 Subject: [PATCH 08/24] STYLE: enable pycodestyle --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3a0b628..51e0215 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,7 @@ ignore_errors = true [tool.ruff] line-length = 120 lint.select = [ -# "E", # pycodestyle + "E", # pycodestyle "F", # Pyflakes "UP", # pyupgrade "B", # flake8-bugbear From 33f849dcc20e7ee54b773c3975431a3868ac02da Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:31:43 -0400 Subject: [PATCH 09/24] DEV: update imports --- data/process_buyables.py | 6 +- data/process_stock.py | 2 +- docs/FragmentRetro/fragmenter-base.md | 2 +- docs/FragmentRetro/fragmenter.md | 2 +- docs/FragmentRetro/retrosynthesis.md | 6 +- docs/FragmentRetro/solutions.md | 6 +- docs/FragmentRetro/substructure-matcher.md | 2 +- docs/FragmentRetro/utils/filter-compound.md | 6 +- docs/FragmentRetro/utils/helper.md | 6 +- docs/app/interface.md | 2 +- docs/dev/logging.md | 6 +- docs/index.md | 8 +- pyproject.toml | 7 +- scripts/paroutes_example.py | 8 +- src/fragmentretro/__init__.py | 2 +- src/fragmentretro/app/gui/controller.py | 13 +- src/fragmentretro/app/gui/state.py | 7 +- src/fragmentretro/fragmenter_base.py | 5 +- src/fragmentretro/retrosynthesis.py | 12 +- src/fragmentretro/solutions.py | 7 +- src/fragmentretro/substructure_matcher.py | 5 +- src/fragmentretro/utils/filter_compound.py | 13 +- tests/test_compound_filter.py | 7 +- tests/test_fragmenter.py | 7 +- tests/test_solutions.py | 3 +- tests/test_substructure_matcher.py | 5 +- uv.lock | 1444 +++++++++++++++++++ 27 files changed, 1522 insertions(+), 77 deletions(-) create mode 100644 uv.lock diff --git a/data/process_buyables.py b/data/process_buyables.py index e0a3837..dd37267 100644 --- a/data/process_buyables.py +++ b/data/process_buyables.py @@ -3,9 +3,9 @@ import shutil from pathlib import Path -from FragmentRetro.utils.filter_compound import precompute_properties -from FragmentRetro.utils.helpers import canonicalize_smiles -from FragmentRetro.utils.logging_config import logger +from fragmentretro.utils.filter_compound import precompute_properties +from fragmentretro.utils.helpers import canonicalize_smiles +from fragmentretro.utils.logging_config import logger from tqdm import tqdm DATA_PATH = Path(__file__).parent diff --git a/data/process_stock.py b/data/process_stock.py index 3c35d6e..2f798cf 100644 --- a/data/process_stock.py +++ b/data/process_stock.py @@ -1,6 +1,6 @@ from pathlib import Path -from FragmentRetro.utils.filter_compound import precompute_properties +from fragmentretro.utils.filter_compound import precompute_properties DATA_PATH = Path(__file__).parent PAROUTES_PATH = DATA_PATH / "paroutes" diff --git a/docs/FragmentRetro/fragmenter-base.md b/docs/FragmentRetro/fragmenter-base.md index aceaec9..12386ea 100644 --- a/docs/FragmentRetro/fragmenter-base.md +++ b/docs/FragmentRetro/fragmenter-base.md @@ -5,7 +5,7 @@ You will only have to define the abstract methods to find fragmentation bonds and to break these bonds. Other methods like building fragment graph (`networkx` graph), visualization, and how to get SMILES string given a combination of fragments are provided in this base class. ```python -from FragmentRetro.fragmenter_base import Fragmenter +from fragmentretro.fragmenter_base import Fragmenter # suppose you have a new way to find and break bonds: `FindTestBonds` and `BreakTestBonds` diff --git a/docs/FragmentRetro/fragmenter.md b/docs/FragmentRetro/fragmenter.md index 109c793..f4a7a70 100644 --- a/docs/FragmentRetro/fragmenter.md +++ b/docs/FragmentRetro/fragmenter.md @@ -5,7 +5,7 @@ Once you have the fragmentation algorithms such as BRICS, you can get derived cl ## Example Use ```python -from FragmentRetro.fragmenter import BRICSFragmenter +from fragmentretro.fragmenter import BRICSFragmenter smiles = "COc1ccc(-n2nccn2)c(C(=O)N2CCC[C@@]2(C)c2nc3c(C)c(Cl)ccc3[nH]2)c1" fragmenter = BRICSFragmenter(smiles) diff --git a/docs/FragmentRetro/retrosynthesis.md b/docs/FragmentRetro/retrosynthesis.md index 2b1d57f..5a8a3aa 100644 --- a/docs/FragmentRetro/retrosynthesis.md +++ b/docs/FragmentRetro/retrosynthesis.md @@ -5,9 +5,9 @@ The `Retrosynthesis` class identifies all possible retrosynthesis solutions for ## Example Use ```python -from FragmentRetro.fragmenter import BRICSFragmenter -from FragmentRetro.retrosynthesis import Retrosynthesis -from FragmentRetro.solutions import RetrosynthesisSolution +from fragmentretro.fragmenter import BRICSFragmenter +from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.solutions import RetrosynthesisSolution # Define your building block set (SMILES strings) original_BBs = set(['Brc1cc(OC)ccc1-n1nccn1', diff --git a/docs/FragmentRetro/solutions.md b/docs/FragmentRetro/solutions.md index 4b7f7ba..bcc16d8 100644 --- a/docs/FragmentRetro/solutions.md +++ b/docs/FragmentRetro/solutions.md @@ -5,9 +5,9 @@ The `RetrosynthesisSolution` class is designed to find and visualize all possibl ## Example Use ```python -from FragmentRetro.retrosynthesis import Retrosynthesis -from FragmentRetro.fragmenter import BRICSFragmenter -from FragmentRetro.solutions import RetrosynthesisSolution +from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.fragmenter import BRICSFragmenter +from fragmentretro.solutions import RetrosynthesisSolution # Example SMILES smiles = "COc1ccc(-n2nccn2)c(C(=O)N2CCC[C@@]2(C)c2nc3c(C)c(Cl)ccc3[nH]2)c1" diff --git a/docs/FragmentRetro/substructure-matcher.md b/docs/FragmentRetro/substructure-matcher.md index 62630d1..9452db7 100644 --- a/docs/FragmentRetro/substructure-matcher.md +++ b/docs/FragmentRetro/substructure-matcher.md @@ -5,7 +5,7 @@ Check if a fragment (which can contain dummy or any atoms represented by "*") is ## Example Use ```python -from FragmentRetro.substructure_matcher import SubstructureMatcher +from fragmentretro.substructure_matcher import SubstructureMatcher fragment_smiles = "[4*]CCN[5*]", molecule_smiles = "CCCNC" diff --git a/docs/FragmentRetro/utils/filter-compound.md b/docs/FragmentRetro/utils/filter-compound.md index df79705..ebf56cc 100644 --- a/docs/FragmentRetro/utils/filter-compound.md +++ b/docs/FragmentRetro/utils/filter-compound.md @@ -8,7 +8,7 @@ The `precompute_properties` function computes properties for a large set of comp ```python from pathlib import Path -from FragmentRetro.utils.filter_compound import precompute_properties +from fragmentretro.utils.filter_compound import precompute_properties DATA_PATH = Path(__file__).parent.parent / "data" PAROUTES_PATH = DATA_PATH / "paroutes" @@ -27,8 +27,8 @@ precompute_properties(n1_stock_subset, MOL_PROPERTIES_PATH, fpSize=2048) The `CompoundFilter` class is used to initialize a filter, and the `get_filtered_BBs` method retrieves the screened building blocks. The following example demonstrates filtering using a specific fragment SMILES string. ```python -from FragmentRetro.utils.filter_compound import CompoundFilter -from FragmentRetro.utils.helpers import replace_dummy_atoms_regex +from fragmentretro.utils.filter_compound import CompoundFilter +from fragmentretro.utils.helpers import replace_dummy_atoms_regex fragment_smiles_list = ["[5*]N1CCC[C@@]1([13*])C", "[4*]CCN[5*]", "[4*]C[8*]", "[*]C[*]", "[3*]O[3*]"] fragment_smiles = fragment_smiles_list[1] diff --git a/docs/FragmentRetro/utils/helper.md b/docs/FragmentRetro/utils/helper.md index 8f250cc..6c0a7cf 100644 --- a/docs/FragmentRetro/utils/helper.md +++ b/docs/FragmentRetro/utils/helper.md @@ -7,7 +7,7 @@ This module provides helper functions for working with SMILES strings. `canonicalize_smiles` is for canonicalizing SMILES strings. ```python -from FragmentRetro.utils.helpers import canonicalize_smiles +from fragmentretro.utils.helpers import canonicalize_smiles smiles = 'C[C@@H](O)C(=O)O' canonical_smiles = canonicalize_smiles(smiles) @@ -19,7 +19,7 @@ print(f"Canonical SMILES: {canonical_smiles}") `replace_dummy_atoms_regex` is for replacing dummy atoms with hydrogen atoms for pattern fingerprint screening. See how it's used in the `filter_compounds` function in the `CompoundFilter` class. ```python -from FragmentRetro.utils.helpers import replace_dummy_atoms_regex +from fragmentretro.utils.helpers import replace_dummy_atoms_regex smiles_with_dummy = '[5*]N1CCC[C@@]1([13*])C' smiles_without_dummy = replace_dummy_atoms_regex(smiles_with_dummy) @@ -30,7 +30,7 @@ print(f"SMILES without dummy atoms: {smiles_without_dummy}") `remove_indices_before_dummy` is for removing indices before dummy atoms. This is to record processed fragment SMILES strings in the most general format. See how it's used in the `Retrosythesis` class as well. ```python -from FragmentRetro.utils.helpers import remove_indices_before_dummy +from fragmentretro.utils.helpers import remove_indices_before_dummy smiles_with_indices = '[5*]N1CCC[C@@]1([13*])C' smiles_without_indices = remove_indices_before_dummy(smiles_with_indices) diff --git a/docs/app/interface.md b/docs/app/interface.md index bacb2f5..1e0f9cc 100644 --- a/docs/app/interface.md +++ b/docs/app/interface.md @@ -10,7 +10,7 @@ In a Jupyter notebook: from app.interface import display_gui import logging -from FragmentRetro.utils.logging_config import logger as fragment_logger +from fragmentretro.utils.logging_config import logger as fragment_logger from app.logging_config import logger as app_logger # Adjust the logging levels to control the verbosity of the logs or to suppress them diff --git a/docs/dev/logging.md b/docs/dev/logging.md index da66aae..b4de902 100644 --- a/docs/dev/logging.md +++ b/docs/dev/logging.md @@ -28,7 +28,7 @@ Valid log levels are: When writing a module, follow these guidelines: ```python -from FragmentRetro.utils.logging_config import logger +from fragmentretro.utils.logging_config import logger def my_function(): # Use appropriate log levels @@ -42,7 +42,7 @@ def my_function(): Key points: - Don't configure the logger in your modules -- Always use `from FragmentRetro.utils.logging_config import logger` +- Always use `from fragmentretro.utils.logging_config import logger` - Choose appropriate log levels - Don't use print statements for debugging - Don't add parameters like `verbose` to your functions @@ -52,7 +52,7 @@ Key points: For Jupyter notebooks, put this in your first cell: ```python -from FragmentRetro.utils.logging_config import logger +from fragmentretro.utils.logging_config import logger logger.setLevel(logging.DEBUG) # To see debug messages logger.setLevel(logging.INFO) # Back to info only diff --git a/docs/index.md b/docs/index.md index 7ca1afc..bd677b5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -29,9 +29,9 @@ Here's a quick example to obtain retrosynthesis solutions: ```python from pathlib import Path -from FragmentRetro.fragmenter import BRICSFragmenter # or rBRICSFragmenter -from FragmentRetro.retrosynthesis import Retrosynthesis -from FragmentRetro.solutions import RetrosynthesisSolution +from fragmentretro.fragmenter import BRICSFragmenter # or rBRICSFragmenter +from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.solutions import RetrosynthesisSolution DATA_PATH = Path(__name__).parent / "data" PAROUTES_PATH = DATA_PATH / "paroutes" @@ -62,7 +62,7 @@ FragmentRetro's Graphical User Interface (GUI) is built using `ipywidget`. To ac from app.interface import display_gui import logging -from FragmentRetro.utils.logging_config import logger as fragment_logger +from fragmentretro.utils.logging_config import logger as fragment_logger from app.logging_config import logger as app_logger # Adjust the logging levels to control the verbosity of the logs or to suppress them diff --git a/pyproject.toml b/pyproject.toml index 51e0215..1d37579 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,11 +36,10 @@ dev = [ "mkdocstrings-python==1.12.2", "mkdocs-material==9.5.49", "pytest==8.3.4", - "ruff==0.4.7", + "ruff>=0.4.7", "mypy==1.13.0", - "isort==5.13.2", "mypy-extensions==1.0.0", - "pre-commit==4.0.1" + "pre-commit==4.0.1", ] [tool.mypy] @@ -67,4 +66,4 @@ lint.ignore = [ "E501", # o respect fmt off blocks "SIM108", # disagree w/ https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp/ ] -exclude = ["tests"] \ No newline at end of file +exclude = ["tests"] diff --git a/scripts/paroutes_example.py b/scripts/paroutes_example.py index accab59..370dd41 100644 --- a/scripts/paroutes_example.py +++ b/scripts/paroutes_example.py @@ -1,10 +1,10 @@ import pickle from pathlib import Path -from FragmentRetro.fragmenter import BRICSFragmenter # or use rBRICSFragmenter -from FragmentRetro.retrosynthesis import Retrosynthesis -from FragmentRetro.solutions import RetrosynthesisSolution -from FragmentRetro.utils.logging_config import logger +from fragmentretro.fragmenter import BRICSFragmenter # or use rBRICSFragmenter +from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.solutions import RetrosynthesisSolution +from fragmentretro.utils.logging_config import logger from tqdm import tqdm DATA_PATH = Path(__name__).parent / "data" diff --git a/src/fragmentretro/__init__.py b/src/fragmentretro/__init__.py index 25740da..3e134f9 100644 --- a/src/fragmentretro/__init__.py +++ b/src/fragmentretro/__init__.py @@ -1,5 +1,5 @@ """FragmentRetro - A package for getting retrosynthesis solutions with fragmentation rules.""" -from FragmentRetro.utils.logging_config import setup_logging +from fragmentretro.utils.logging_config import setup_logging setup_logging() diff --git a/src/fragmentretro/app/gui/controller.py b/src/fragmentretro/app/gui/controller.py index c3127ee..fe71ef1 100644 --- a/src/fragmentretro/app/gui/controller.py +++ b/src/fragmentretro/app/gui/controller.py @@ -28,17 +28,18 @@ target_smiles_input, ) from app.logging_config import logger -from FragmentRetro.fragmenter import BRICSFragmenter, rBRICSFragmenter -from FragmentRetro.fragmenter_base import Fragmenter -from FragmentRetro.retrosynthesis import Retrosynthesis -from FragmentRetro.solutions import RetrosynthesisSolution -from FragmentRetro.utils.helpers import sort_by_heavy_atoms -from FragmentRetro.utils.type_definitions import CombType, SolutionType from IPython.display import display from PIL.Image import Image as PILImage from rdkit import Chem from rdkit.Chem import Draw +from fragmentretro.fragmenter import BRICSFragmenter, rBRICSFragmenter +from fragmentretro.fragmenter_base import Fragmenter +from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.solutions import RetrosynthesisSolution +from fragmentretro.utils.helpers import sort_by_heavy_atoms +from fragmentretro.utils.type_definitions import CombType, SolutionType + class GuiController: """Manages GUI event handling and interactions.""" diff --git a/src/fragmentretro/app/gui/state.py b/src/fragmentretro/app/gui/state.py index 0b025f1..d0b295b 100644 --- a/src/fragmentretro/app/gui/state.py +++ b/src/fragmentretro/app/gui/state.py @@ -1,8 +1,9 @@ -from FragmentRetro.retrosynthesis import Retrosynthesis -from FragmentRetro.solutions import RetrosynthesisSolution -from FragmentRetro.utils.type_definitions import CombType, SolutionType from PIL.Image import Image as PILImage # For type hinting +from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.solutions import RetrosynthesisSolution +from fragmentretro.utils.type_definitions import CombType, SolutionType + class AppState: """Holds the state of the FragmentRetro GUI application.""" diff --git a/src/fragmentretro/fragmenter_base.py b/src/fragmentretro/fragmenter_base.py index b0c0751..7be11bf 100644 --- a/src/fragmentretro/fragmenter_base.py +++ b/src/fragmentretro/fragmenter_base.py @@ -4,11 +4,12 @@ import matplotlib.pyplot as plt import networkx as nx -from FragmentRetro.utils.logging_config import logger -from FragmentRetro.utils.type_definitions import AtomMappingType, BondType, CombType from rdkit import Chem from rdkit.Chem import Mol +from fragmentretro.utils.logging_config import logger +from fragmentretro.utils.type_definitions import AtomMappingType, BondType, CombType + class Fragmenter(ABC): def __init__(self, smiles: str) -> None: diff --git a/src/fragmentretro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py index 496d1b6..de65679 100644 --- a/src/fragmentretro/retrosynthesis.py +++ b/src/fragmentretro/retrosynthesis.py @@ -1,12 +1,12 @@ from pathlib import Path from typing import cast -from FragmentRetro.fragmenter_base import Fragmenter -from FragmentRetro.substructure_matcher import SubstructureMatcher -from FragmentRetro.utils.filter_compound import CompoundFilter -from FragmentRetro.utils.helpers import remove_indices_before_dummy -from FragmentRetro.utils.logging_config import logger -from FragmentRetro.utils.type_definitions import ( +from fragmentretro.fragmenter_base import Fragmenter +from fragmentretro.substructure_matcher import SubstructureMatcher +from fragmentretro.utils.filter_compound import CompoundFilter +from fragmentretro.utils.helpers import remove_indices_before_dummy +from fragmentretro.utils.logging_config import logger +from fragmentretro.utils.type_definitions import ( BBsType, CombBBsDictType, CombFilterIndicesDictType, diff --git a/src/fragmentretro/solutions.py b/src/fragmentretro/solutions.py index 848211a..1899406 100644 --- a/src/fragmentretro/solutions.py +++ b/src/fragmentretro/solutions.py @@ -1,12 +1,13 @@ from itertools import chain -from FragmentRetro.retrosynthesis import Retrosynthesis -from FragmentRetro.utils.logging_config import logger -from FragmentRetro.utils.type_definitions import CombType, SolutionType from PIL import Image from rdkit import Chem from rdkit.Chem import Draw +from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.utils.logging_config import logger +from fragmentretro.utils.type_definitions import CombType, SolutionType + class RetrosynthesisSolution: def __init__(self, retrosynthesis: Retrosynthesis): diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index f1371c8..e831478 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -2,11 +2,12 @@ from multiprocessing import Pool, cpu_count from typing import cast -from FragmentRetro.utils.logging_config import logger -from FragmentRetro.utils.type_definitions import BBsType from rdkit import Chem from rdkit.Chem.rdchem import Atom +from fragmentretro.utils.logging_config import logger +from fragmentretro.utils.type_definitions import BBsType + class SubstructureMatcher: def __init__( diff --git a/src/fragmentretro/utils/filter_compound.py b/src/fragmentretro/utils/filter_compound.py index b0ee2c5..b5a97af 100644 --- a/src/fragmentretro/utils/filter_compound.py +++ b/src/fragmentretro/utils/filter_compound.py @@ -2,16 +2,17 @@ from pathlib import Path import numpy as np -from FragmentRetro.utils.helpers import canonicalize_smiles, replace_dummy_atoms_regex -from FragmentRetro.utils.logging_config import logger -from FragmentRetro.utils.type_definitions import ( +from rdkit import Chem +from rdkit.Chem import rdMolDescriptors +from tqdm import tqdm + +from fragmentretro.utils.helpers import canonicalize_smiles, replace_dummy_atoms_regex +from fragmentretro.utils.logging_config import logger +from fragmentretro.utils.type_definitions import ( BBsType, FilterIndicesType, MolProperties, ) -from rdkit import Chem -from rdkit.Chem import rdMolDescriptors -from tqdm import tqdm def get_mol_properties(smiles: str, fpSize: int = 2048) -> MolProperties: diff --git a/tests/test_compound_filter.py b/tests/test_compound_filter.py index 84e4894..066a06e 100644 --- a/tests/test_compound_filter.py +++ b/tests/test_compound_filter.py @@ -3,9 +3,8 @@ from pathlib import Path import pytest - -from FragmentRetro.substructure_matcher import SubstructureMatcher -from FragmentRetro.utils.filter_compound import CompoundFilter, precompute_properties +from fragmentretro.substructure_matcher import SubstructureMatcher +from fragmentretro.utils.filter_compound import CompoundFilter, precompute_properties DATA_PATH = Path(__file__).parent.parent / "data" PAROUTES_PATH = DATA_PATH / "paroutes" @@ -13,7 +12,7 @@ MOL_PROPERTIES_PATH = PRECOMPUTE_PATH / "n1_stock_properties_subset.json" -with open(PAROUTES_PATH / "n1-stock.txt", "r") as f: +with open(PAROUTES_PATH / "n1-stock.txt") as f: n1_stock = [line.strip() for line in f.readlines()] n1_stock_subset = n1_stock[:500] PRECOMPUTE_PATH.mkdir(parents=True, exist_ok=True) diff --git a/tests/test_fragmenter.py b/tests/test_fragmenter.py index 28ca83b..15e286a 100644 --- a/tests/test_fragmenter.py +++ b/tests/test_fragmenter.py @@ -3,10 +3,9 @@ from itertools import combinations as itertools_combinations import pytest - -from FragmentRetro.fragmenter import BRICSFragmenter, rBRICSFragmenter -from FragmentRetro.substructure_matcher import SubstructureMatcher -from FragmentRetro.utils.helpers import count_heavy_atoms, replace_dummy_atoms_regex +from fragmentretro.fragmenter import BRICSFragmenter, rBRICSFragmenter +from fragmentretro.substructure_matcher import SubstructureMatcher +from fragmentretro.utils.helpers import count_heavy_atoms, replace_dummy_atoms_regex TEST_CASES_FOR_GET_LENGTH_N_COMBINATIONS = [ { diff --git a/tests/test_solutions.py b/tests/test_solutions.py index 04e43df..a134f92 100644 --- a/tests/test_solutions.py +++ b/tests/test_solutions.py @@ -1,8 +1,7 @@ """Tests for solutions.""" import pytest - -from FragmentRetro.solutions import RetrosynthesisSolution +from fragmentretro.solutions import RetrosynthesisSolution TEST_CASES_FOR_GET_SOLUTIONS = [ { diff --git a/tests/test_substructure_matcher.py b/tests/test_substructure_matcher.py index 71661d7..dbd7555 100644 --- a/tests/test_substructure_matcher.py +++ b/tests/test_substructure_matcher.py @@ -3,8 +3,7 @@ from pathlib import Path import pytest - -from FragmentRetro.substructure_matcher import SubstructureMatcher +from fragmentretro.substructure_matcher import SubstructureMatcher DATA_PATH = Path(__file__).parent.parent / "data" PAROUTES_PATH = DATA_PATH / "paroutes" @@ -246,7 +245,7 @@ def test_is_strict_substructure(case_number, fragment_smiles, molecule_smiles_li ], ) def test_parallel_get_substructure_BBs(fragment_smiles): - with open(PAROUTES_PATH / "n1-stock.txt", "r") as f: + with open(PAROUTES_PATH / "n1-stock.txt") as f: n1_stock = [line.strip() for line in f.readlines()] n1_stock_subset = set(n1_stock[:500]) no_parallel_matcher = SubstructureMatcher(n1_stock_subset, parallelize=False) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..6594a2d --- /dev/null +++ b/uv.lock @@ -0,0 +1,1444 @@ +version = 1 +revision = 2 +requires-python = ">=3.12" + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "certifi" +version = "2025.4.26" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, + { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, + { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, + { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, + { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, + { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, + { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, + { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, + { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, + { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, + { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, + { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, + { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, + { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, + { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, + { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, + { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, + { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, + { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +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 = "comm" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210, upload-time = "2024-03-12T16:53:41.133Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180, upload-time = "2024-03-12T16:53:39.226Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, + { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, + { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, + { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, + { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, + { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" }, + { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" }, + { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" }, + { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" }, + { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" }, + { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" }, + { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" }, + { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" }, + { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" }, + { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" }, + { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" }, + { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" }, + { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" }, + { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "debugpy" +version = "1.8.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/75/087fe07d40f490a78782ff3b0a30e3968936854105487decdb33446d4b0e/debugpy-1.8.14.tar.gz", hash = "sha256:7cd287184318416850aa8b60ac90105837bb1e59531898c07569d197d2ed5322", size = 1641444, upload-time = "2025-04-10T19:46:10.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/2a/ac2df0eda4898f29c46eb6713a5148e6f8b2b389c8ec9e425a4a1d67bf07/debugpy-1.8.14-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:8899c17920d089cfa23e6005ad9f22582fd86f144b23acb9feeda59e84405b84", size = 2501268, upload-time = "2025-04-10T19:46:26.044Z" }, + { url = "https://files.pythonhosted.org/packages/10/53/0a0cb5d79dd9f7039169f8bf94a144ad3efa52cc519940b3b7dde23bcb89/debugpy-1.8.14-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6bb5c0dcf80ad5dbc7b7d6eac484e2af34bdacdf81df09b6a3e62792b722826", size = 4221077, upload-time = "2025-04-10T19:46:27.464Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d5/84e01821f362327bf4828728aa31e907a2eca7c78cd7c6ec062780d249f8/debugpy-1.8.14-cp312-cp312-win32.whl", hash = "sha256:281d44d248a0e1791ad0eafdbbd2912ff0de9eec48022a5bfbc332957487ed3f", size = 5255127, upload-time = "2025-04-10T19:46:29.467Z" }, + { url = "https://files.pythonhosted.org/packages/33/16/1ed929d812c758295cac7f9cf3dab5c73439c83d9091f2d91871e648093e/debugpy-1.8.14-cp312-cp312-win_amd64.whl", hash = "sha256:5aa56ef8538893e4502a7d79047fe39b1dae08d9ae257074c6464a7b290b806f", size = 5297249, upload-time = "2025-04-10T19:46:31.538Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e4/395c792b243f2367d84202dc33689aa3d910fb9826a7491ba20fc9e261f5/debugpy-1.8.14-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:329a15d0660ee09fec6786acdb6e0443d595f64f5d096fc3e3ccf09a4259033f", size = 2485676, upload-time = "2025-04-10T19:46:32.96Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f1/6f2ee3f991327ad9e4c2f8b82611a467052a0fb0e247390192580e89f7ff/debugpy-1.8.14-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f920c7f9af409d90f5fd26e313e119d908b0dd2952c2393cd3247a462331f15", size = 4217514, upload-time = "2025-04-10T19:46:34.336Z" }, + { url = "https://files.pythonhosted.org/packages/79/28/b9d146f8f2dc535c236ee09ad3e5ac899adb39d7a19b49f03ac95d216beb/debugpy-1.8.14-cp313-cp313-win32.whl", hash = "sha256:3784ec6e8600c66cbdd4ca2726c72d8ca781e94bce2f396cc606d458146f8f4e", size = 5254756, upload-time = "2025-04-10T19:46:36.199Z" }, + { url = "https://files.pythonhosted.org/packages/e0/62/a7b4a57013eac4ccaef6977966e6bec5c63906dd25a86e35f155952e29a1/debugpy-1.8.14-cp313-cp313-win_amd64.whl", hash = "sha256:684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e", size = 5297119, upload-time = "2025-04-10T19:46:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/97/1a/481f33c37ee3ac8040d3d51fc4c4e4e7e61cb08b8bc8971d6032acc2279f/debugpy-1.8.14-py2.py3-none-any.whl", hash = "sha256:5cd9a579d553b6cb9759a7908a41988ee6280b961f24f63336835d9418216a20", size = 5256230, upload-time = "2025-04-10T19:46:54.077Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "distlib" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" }, +] + +[[package]] +name = "executing" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693, upload-time = "2025-01-22T15:41:29.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702, upload-time = "2025-01-22T15:41:25.929Z" }, +] + +[[package]] +name = "filelock" +version = "3.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, +] + +[[package]] +name = "fonttools" +version = "4.57.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/2d/a9a0b6e3a0cf6bd502e64fc16d894269011930cabfc89aee20d1635b1441/fonttools-4.57.0.tar.gz", hash = "sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de", size = 3492448, upload-time = "2025-04-03T11:07:13.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/98/d4bc42d43392982eecaaca117d79845734d675219680cd43070bb001bc1f/fonttools-4.57.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31", size = 2751824, upload-time = "2025-04-03T11:06:03.782Z" }, + { url = "https://files.pythonhosted.org/packages/1a/62/7168030eeca3742fecf45f31e63b5ef48969fa230a672216b805f1d61548/fonttools-4.57.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92", size = 2283072, upload-time = "2025-04-03T11:06:05.533Z" }, + { url = "https://files.pythonhosted.org/packages/5d/82/121a26d9646f0986ddb35fbbaf58ef791c25b59ecb63ffea2aab0099044f/fonttools-4.57.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888", size = 4788020, upload-time = "2025-04-03T11:06:07.249Z" }, + { url = "https://files.pythonhosted.org/packages/5b/26/e0f2fb662e022d565bbe280a3cfe6dafdaabf58889ff86fdef2d31ff1dde/fonttools-4.57.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6", size = 4859096, upload-time = "2025-04-03T11:06:09.469Z" }, + { url = "https://files.pythonhosted.org/packages/9e/44/9075e323347b1891cdece4b3f10a3b84a8f4c42a7684077429d9ce842056/fonttools-4.57.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98", size = 4964356, upload-time = "2025-04-03T11:06:11.294Z" }, + { url = "https://files.pythonhosted.org/packages/48/28/caa8df32743462fb966be6de6a79d7f30393859636d7732e82efa09fbbb4/fonttools-4.57.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8", size = 5226546, upload-time = "2025-04-03T11:06:13.6Z" }, + { url = "https://files.pythonhosted.org/packages/f6/46/95ab0f0d2e33c5b1a4fc1c0efe5e286ba9359602c0a9907adb1faca44175/fonttools-4.57.0-cp312-cp312-win32.whl", hash = "sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac", size = 2146776, upload-time = "2025-04-03T11:06:15.643Z" }, + { url = "https://files.pythonhosted.org/packages/06/5d/1be5424bb305880e1113631f49a55ea7c7da3a5fe02608ca7c16a03a21da/fonttools-4.57.0-cp312-cp312-win_amd64.whl", hash = "sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9", size = 2193956, upload-time = "2025-04-03T11:06:17.534Z" }, + { url = "https://files.pythonhosted.org/packages/e9/2f/11439f3af51e4bb75ac9598c29f8601aa501902dcedf034bdc41f47dd799/fonttools-4.57.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef", size = 2739175, upload-time = "2025-04-03T11:06:19.583Z" }, + { url = "https://files.pythonhosted.org/packages/25/52/677b55a4c0972dc3820c8dba20a29c358197a78229daa2ea219fdb19e5d5/fonttools-4.57.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c", size = 2276583, upload-time = "2025-04-03T11:06:21.753Z" }, + { url = "https://files.pythonhosted.org/packages/64/79/184555f8fa77b827b9460a4acdbbc0b5952bb6915332b84c615c3a236826/fonttools-4.57.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72", size = 4766437, upload-time = "2025-04-03T11:06:23.521Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/c25116352f456c0d1287545a7aa24e98987b6d99c5b0456c4bd14321f20f/fonttools-4.57.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817", size = 4838431, upload-time = "2025-04-03T11:06:25.423Z" }, + { url = "https://files.pythonhosted.org/packages/53/ae/398b2a833897297797a44f519c9af911c2136eb7aa27d3f1352c6d1129fa/fonttools-4.57.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9", size = 4951011, upload-time = "2025-04-03T11:06:27.41Z" }, + { url = "https://files.pythonhosted.org/packages/b7/5d/7cb31c4bc9ffb9a2bbe8b08f8f53bad94aeb158efad75da645b40b62cb73/fonttools-4.57.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13", size = 5205679, upload-time = "2025-04-03T11:06:29.804Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e4/6934513ec2c4d3d69ca1bc3bd34d5c69dafcbf68c15388dd3bb062daf345/fonttools-4.57.0-cp313-cp313-win32.whl", hash = "sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199", size = 2144833, upload-time = "2025-04-03T11:06:31.737Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0d/2177b7fdd23d017bcfb702fd41e47d4573766b9114da2fddbac20dcc4957/fonttools-4.57.0-cp313-cp313-win_amd64.whl", hash = "sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3", size = 2190799, upload-time = "2025-04-03T11:06:34.784Z" }, + { url = "https://files.pythonhosted.org/packages/90/27/45f8957c3132917f91aaa56b700bcfc2396be1253f685bd5c68529b6f610/fonttools-4.57.0-py3-none-any.whl", hash = "sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f", size = 1093605, upload-time = "2025-04-03T11:07:11.341Z" }, +] + +[[package]] +name = "fragmentretro" +version = "0.0.1" +source = { virtual = "." } +dependencies = [ + { name = "ipykernel" }, + { name = "ipywidgets" }, + { name = "matplotlib" }, + { name = "networkx" }, + { name = "numpy" }, + { name = "rdkit" }, + { name = "tomli" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] + +[package.optional-dependencies] +dev = [ + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "mkdocstrings-python" }, + { name = "mypy" }, + { name = "mypy-extensions" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "ipywidgets", specifier = "==8.1.6" }, + { name = "matplotlib", specifier = "==3.10.0" }, + { name = "mkdocs", marker = "extra == 'dev'", specifier = "==1.6.1" }, + { name = "mkdocs-material", marker = "extra == 'dev'", specifier = "==9.5.49" }, + { name = "mkdocstrings-python", marker = "extra == 'dev'", specifier = "==1.12.2" }, + { name = "mypy", marker = "extra == 'dev'", specifier = "==1.13.0" }, + { name = "mypy-extensions", marker = "extra == 'dev'", specifier = "==1.0.0" }, + { name = "networkx", specifier = "==3.4.2" }, + { name = "numpy", specifier = "==1.26.4" }, + { name = "pre-commit", marker = "extra == 'dev'", specifier = "==4.0.1" }, + { name = "pytest", marker = "extra == 'dev'", specifier = "==8.3.4" }, + { name = "rdkit", specifier = "==2023.9.3" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.4.7" }, + { name = "tomli", specifier = ">=2.2.1" }, + { name = "tqdm", specifier = "==4.67.1" }, + { name = "typing-extensions", specifier = "==4.12.2" }, +] +provides-extras = ["dev"] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffe" +version = "1.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/3e/5aa9a61f7c3c47b0b52a1d930302992229d191bf4bc76447b324b731510a/griffe-1.7.3.tar.gz", hash = "sha256:52ee893c6a3a968b639ace8015bec9d36594961e156e23315c8e8e51401fa50b", size = 395137, upload-time = "2025-04-23T11:29:09.147Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/c6/5c20af38c2a57c15d87f7f38bee77d63c1d2a3689f74fefaf35915dd12b2/griffe-1.7.3-py3-none-any.whl", hash = "sha256:c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75", size = 129303, upload-time = "2025-04-23T11:29:07.145Z" }, +] + +[[package]] +name = "identify" +version = "2.6.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/83/b6ea0334e2e7327084a46aaaf71f2146fc061a192d6518c0d020120cd0aa/identify-2.6.10.tar.gz", hash = "sha256:45e92fd704f3da71cc3880036633f48b4b7265fd4de2b57627cb157216eb7eb8", size = 99201, upload-time = "2025-04-19T15:10:38.32Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/d3/85feeba1d097b81a44bcffa6a0beab7b4dfffe78e82fc54978d3ac380736/identify-2.6.10-py2.py3-none-any.whl", hash = "sha256:5f34248f54136beed1a7ba6a6b5c4b6cf21ff495aac7c359e1ef831ae3b8ab25", size = 99101, upload-time = "2025-04-19T15:10:36.701Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +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 = "ipykernel" +version = "6.29.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367, upload-time = "2024-07-01T14:07:22.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173, upload-time = "2024-07-01T14:07:19.603Z" }, +] + +[[package]] +name = "ipython" +version = "9.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/02/63a84444a7409b3c0acd1de9ffe524660e0e5d82ee473e78b45e5bfb64a4/ipython-9.2.0.tar.gz", hash = "sha256:62a9373dbc12f28f9feaf4700d052195bf89806279fc8ca11f3f54017d04751b", size = 4424394, upload-time = "2025-04-25T17:55:40.498Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/ce/5e897ee51b7d26ab4e47e5105e7368d40ce6cfae2367acdf3165396d50be/ipython-9.2.0-py3-none-any.whl", hash = "sha256:fef5e33c4a1ae0759e0bba5917c9db4eb8c53fee917b6a526bd973e1ca5159f6", size = 604277, upload-time = "2025-04-25T17:55:37.625Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "ipywidgets" +version = "8.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/98/4074d9cb7e89f7ee387b41e9a4b74c8e0d6196e90b910af1cc674e1cdd3d/ipywidgets-8.1.6.tar.gz", hash = "sha256:d8ace49c66f14419fc66071371b99d01bed230bbc15d8a60233b18bfbd782851", size = 116764, upload-time = "2025-04-10T13:02:35.733Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/b8/62952729573d983d9433faacf62a52ee2e8cf46504418061ad1739967abe/ipywidgets-8.1.6-py3-none-any.whl", hash = "sha256:446e7630a1d025bdc7635e1169fcc06f2ce33b5bd41c2003edeb4a47c8d4bbb1", size = 139808, upload-time = "2025-04-10T13:02:33.904Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jupyter-client" +version = "8.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, +] + +[[package]] +name = "jupyter-core" +version = "5.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629, upload-time = "2024-03-12T12:37:35.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", size = 28965, upload-time = "2024-03-12T12:37:32.36Z" }, +] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/94/766b8199e8a902a4c5ee12a9407a348bbabe9fa22400758576b153d17d8e/jupyterlab_widgets-3.0.14.tar.gz", hash = "sha256:bad03e59546869f026e537e0d170e454259e6dc7048e14041707ca31e523c8a1", size = 203815, upload-time = "2025-04-10T13:00:40.522Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/7a/f2479ba401e02f7fcbd3fc6af201eac888eaa188574b8e9df19452ab4972/jupyterlab_widgets-3.0.14-py3-none-any.whl", hash = "sha256:54c33e3306b7fca139d165d6190dc6c0627aafa5d14adfc974a4e9a3d26cb703", size = 213999, upload-time = "2025-04-10T13:00:38.626Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538, upload-time = "2024-12-24T18:30:51.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152, upload-time = "2024-12-24T18:29:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555, upload-time = "2024-12-24T18:29:19.146Z" }, + { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067, upload-time = "2024-12-24T18:29:20.096Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443, upload-time = "2024-12-24T18:29:22.843Z" }, + { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728, upload-time = "2024-12-24T18:29:24.463Z" }, + { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388, upload-time = "2024-12-24T18:29:25.776Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849, upload-time = "2024-12-24T18:29:27.202Z" }, + { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533, upload-time = "2024-12-24T18:29:28.638Z" }, + { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898, upload-time = "2024-12-24T18:29:30.368Z" }, + { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605, upload-time = "2024-12-24T18:29:33.151Z" }, + { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801, upload-time = "2024-12-24T18:29:34.584Z" }, + { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077, upload-time = "2024-12-24T18:29:36.138Z" }, + { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410, upload-time = "2024-12-24T18:29:39.991Z" }, + { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853, upload-time = "2024-12-24T18:29:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424, upload-time = "2024-12-24T18:29:44.38Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/e62464a652f4f8cd9006e13d07abad844a47df1e6537f73ddfbf1bc997ec/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", size = 124156, upload-time = "2024-12-24T18:29:45.368Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2d/f13d06998b546a2ad4f48607a146e045bbe48030774de29f90bdc573df15/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", size = 66555, upload-time = "2024-12-24T18:29:46.37Z" }, + { url = "https://files.pythonhosted.org/packages/59/e3/b8bd14b0a54998a9fd1e8da591c60998dc003618cb19a3f94cb233ec1511/kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", size = 65071, upload-time = "2024-12-24T18:29:47.333Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1c/6c86f6d85ffe4d0ce04228d976f00674f1df5dc893bf2dd4f1928748f187/kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", size = 1378053, upload-time = "2024-12-24T18:29:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b9/1c6e9f6dcb103ac5cf87cb695845f5fa71379021500153566d8a8a9fc291/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", size = 1472278, upload-time = "2024-12-24T18:29:51.164Z" }, + { url = "https://files.pythonhosted.org/packages/ee/81/aca1eb176de671f8bda479b11acdc42c132b61a2ac861c883907dde6debb/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", size = 1478139, upload-time = "2024-12-24T18:29:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/49/f4/e081522473671c97b2687d380e9e4c26f748a86363ce5af48b4a28e48d06/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", size = 1413517, upload-time = "2024-12-24T18:29:53.941Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", size = 1474952, upload-time = "2024-12-24T18:29:56.523Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/13fa685ae167bee5d94b415991c4fc7bb0a1b6ebea6e753a87044b209678/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794", size = 2269132, upload-time = "2024-12-24T18:29:57.989Z" }, + { url = "https://files.pythonhosted.org/packages/ef/92/bb7c9395489b99a6cb41d502d3686bac692586db2045adc19e45ee64ed23/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", size = 2425997, upload-time = "2024-12-24T18:29:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/ed/12/87f0e9271e2b63d35d0d8524954145837dd1a6c15b62a2d8c1ebe0f182b4/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", size = 2376060, upload-time = "2024-12-24T18:30:01.338Z" }, + { url = "https://files.pythonhosted.org/packages/02/6e/c8af39288edbce8bf0fa35dee427b082758a4b71e9c91ef18fa667782138/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", size = 2520471, upload-time = "2024-12-24T18:30:04.574Z" }, + { url = "https://files.pythonhosted.org/packages/13/78/df381bc7b26e535c91469f77f16adcd073beb3e2dd25042efd064af82323/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", size = 2338793, upload-time = "2024-12-24T18:30:06.25Z" }, + { url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", size = 71855, upload-time = "2024-12-24T18:30:07.535Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b6/21529d595b126ac298fdd90b705d87d4c5693de60023e0efcb4f387ed99e/kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", size = 65430, upload-time = "2024-12-24T18:30:08.504Z" }, + { url = "https://files.pythonhosted.org/packages/34/bd/b89380b7298e3af9b39f49334e3e2a4af0e04819789f04b43d560516c0c8/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", size = 126294, upload-time = "2024-12-24T18:30:09.508Z" }, + { url = "https://files.pythonhosted.org/packages/83/41/5857dc72e5e4148eaac5aa76e0703e594e4465f8ab7ec0fc60e3a9bb8fea/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", size = 67736, upload-time = "2024-12-24T18:30:11.039Z" }, + { url = "https://files.pythonhosted.org/packages/e1/d1/be059b8db56ac270489fb0b3297fd1e53d195ba76e9bbb30e5401fa6b759/kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", size = 66194, upload-time = "2024-12-24T18:30:14.886Z" }, + { url = "https://files.pythonhosted.org/packages/e1/83/4b73975f149819eb7dcf9299ed467eba068ecb16439a98990dcb12e63fdd/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", size = 1465942, upload-time = "2024-12-24T18:30:18.927Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2c/30a5cdde5102958e602c07466bce058b9d7cb48734aa7a4327261ac8e002/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", size = 1595341, upload-time = "2024-12-24T18:30:22.102Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9b/1e71db1c000385aa069704f5990574b8244cce854ecd83119c19e83c9586/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", size = 1598455, upload-time = "2024-12-24T18:30:24.947Z" }, + { url = "https://files.pythonhosted.org/packages/85/92/c8fec52ddf06231b31cbb779af77e99b8253cd96bd135250b9498144c78b/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", size = 1522138, upload-time = "2024-12-24T18:30:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/0b/51/9eb7e2cd07a15d8bdd976f6190c0164f92ce1904e5c0c79198c4972926b7/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", size = 1582857, upload-time = "2024-12-24T18:30:28.86Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/c5a00387a5405e68ba32cc64af65ce881a39b98d73cc394b24143bebc5b8/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", size = 2293129, upload-time = "2024-12-24T18:30:30.34Z" }, + { url = "https://files.pythonhosted.org/packages/44/83/eeb7af7d706b8347548313fa3a3a15931f404533cc54fe01f39e830dd231/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", size = 2421538, upload-time = "2024-12-24T18:30:33.334Z" }, + { url = "https://files.pythonhosted.org/packages/05/f9/27e94c1b3eb29e6933b6986ffc5fa1177d2cd1f0c8efc5f02c91c9ac61de/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", size = 2390661, upload-time = "2024-12-24T18:30:34.939Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d4/3c9735faa36ac591a4afcc2980d2691000506050b7a7e80bcfe44048daa7/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", size = 2546710, upload-time = "2024-12-24T18:30:37.281Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fa/be89a49c640930180657482a74970cdcf6f7072c8d2471e1babe17a222dc/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", size = 2349213, upload-time = "2024-12-24T18:30:40.019Z" }, +] + +[[package]] +name = "markdown" +version = "3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/15/222b423b0b88689c266d9eac4e61396fe2cc53464459d6a37618ac863b24/markdown-3.8.tar.gz", hash = "sha256:7df81e63f0df5c4b24b7d156eb81e4690595239b7d70937d0409f1b0de319c6f", size = 360906, upload-time = "2025-04-11T14:42:50.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/3f/afe76f8e2246ffbc867440cbcf90525264df0e658f8a5ca1f872b3f6192a/markdown-3.8-py3-none-any.whl", hash = "sha256:794a929b79c5af141ef5ab0f2f642d0f7b1872981250230e72682346f7cc90dc", size = 106210, upload-time = "2025-04-11T14:42:49.178Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { 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 = "matplotlib" +version = "3.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", size = 36686418, upload-time = "2024-12-14T06:32:51.547Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", size = 8172465, upload-time = "2024-12-14T06:31:24.727Z" }, + { url = "https://files.pythonhosted.org/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", size = 8043300, upload-time = "2024-12-14T06:31:28.55Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", size = 8448936, upload-time = "2024-12-14T06:31:32.223Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", size = 8594151, upload-time = "2024-12-14T06:31:34.894Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", size = 9400347, upload-time = "2024-12-14T06:31:39.552Z" }, + { url = "https://files.pythonhosted.org/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", size = 8039144, upload-time = "2024-12-14T06:31:44.128Z" }, + { url = "https://files.pythonhosted.org/packages/72/11/1b2a094d95dcb6e6edd4a0b238177c439006c6b7a9fe8d31801237bf512f/matplotlib-3.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96f2886f5c1e466f21cc41b70c5a0cd47bfa0015eb2d5793c88ebce658600e25", size = 8173073, upload-time = "2024-12-14T06:31:46.592Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c4/87b6ad2723070511a411ea719f9c70fde64605423b184face4e94986de9d/matplotlib-3.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:12eaf48463b472c3c0f8dbacdbf906e573013df81a0ab82f0616ea4b11281908", size = 8043892, upload-time = "2024-12-14T06:31:49.14Z" }, + { url = "https://files.pythonhosted.org/packages/57/69/cb0812a136550b21361335e9ffb7d459bf6d13e03cb7b015555d5143d2d6/matplotlib-3.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fbbabc82fde51391c4da5006f965e36d86d95f6ee83fb594b279564a4c5d0d2", size = 8450532, upload-time = "2024-12-14T06:31:53.005Z" }, + { url = "https://files.pythonhosted.org/packages/ea/3a/bab9deb4fb199c05e9100f94d7f1c702f78d3241e6a71b784d2b88d7bebd/matplotlib-3.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad2e15300530c1a94c63cfa546e3b7864bd18ea2901317bae8bbf06a5ade6dcf", size = 8593905, upload-time = "2024-12-14T06:31:59.022Z" }, + { url = "https://files.pythonhosted.org/packages/8b/66/742fd242f989adc1847ddf5f445815f73ad7c46aa3440690cc889cfa423c/matplotlib-3.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3547d153d70233a8496859097ef0312212e2689cdf8d7ed764441c77604095ae", size = 9399609, upload-time = "2024-12-14T06:32:05.151Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d6/54cee7142cef7d910a324a7aedf335c0c147b03658b54d49ec48166f10a6/matplotlib-3.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:c55b20591ced744aa04e8c3e4b7543ea4d650b6c3c4b208c08a05b4010e8b442", size = 8039076, upload-time = "2024-12-14T06:32:08.38Z" }, + { url = "https://files.pythonhosted.org/packages/43/14/815d072dc36e88753433bfd0385113405efb947e6895ff7b4d2e8614a33b/matplotlib-3.10.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9ade1003376731a971e398cc4ef38bb83ee8caf0aee46ac6daa4b0506db1fd06", size = 8211000, upload-time = "2024-12-14T06:32:12.383Z" }, + { url = "https://files.pythonhosted.org/packages/9a/76/34e75f364194ec352678adcb540964be6f35ec7d3d8c75ebcb17e6839359/matplotlib-3.10.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95b710fea129c76d30be72c3b38f330269363fbc6e570a5dd43580487380b5ff", size = 8087707, upload-time = "2024-12-14T06:32:15.773Z" }, + { url = "https://files.pythonhosted.org/packages/c3/2b/b6bc0dff6a72d333bc7df94a66e6ce662d224e43daa8ad8ae4eaa9a77f55/matplotlib-3.10.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cdbaf909887373c3e094b0318d7ff230b2ad9dcb64da7ade654182872ab2593", size = 8477384, upload-time = "2024-12-14T06:32:20.311Z" }, + { url = "https://files.pythonhosted.org/packages/c2/2d/b5949fb2b76e9b47ab05e25a5f5f887c70de20d8b0cbc704a4e2ee71c786/matplotlib-3.10.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d907fddb39f923d011875452ff1eca29a9e7f21722b873e90db32e5d8ddff12e", size = 8610334, upload-time = "2024-12-14T06:32:25.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/9a/6e3c799d5134d9af44b01c787e1360bee38cf51850506ea2e743a787700b/matplotlib-3.10.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3b427392354d10975c1d0f4ee18aa5844640b512d5311ef32efd4dd7db106ede", size = 9406777, upload-time = "2024-12-14T06:32:28.919Z" }, + { url = "https://files.pythonhosted.org/packages/0e/dd/e6ae97151e5ed648ab2ea48885bc33d39202b640eec7a2910e2c843f7ac0/matplotlib-3.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5fd41b0ec7ee45cd960a8e71aea7c946a28a0b8a4dcee47d2856b2af051f334c", size = 8109742, upload-time = "2024-12-14T06:32:32.115Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/44/140469d87379c02f1e1870315f3143718036a983dd0416650827b8883192/mkdocs_autorefs-1.4.1.tar.gz", hash = "sha256:4b5b6235a4becb2b10425c2fa191737e415b37aa3418919db33e5d774c9db079", size = 4131355, upload-time = "2025-03-08T13:35:21.232Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/29/1125f7b11db63e8e32bcfa0752a4eea30abff3ebd0796f808e14571ddaa2/mkdocs_autorefs-1.4.1-py3-none-any.whl", hash = "sha256:9793c5ac06a6ebbe52ec0f8439256e66187badf4b5334b5fde0b128ec134df4f", size = 5782047, upload-time = "2025-03-08T13:35:18.889Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.5.49" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/14/8daeeecee2e25bd84239a843fdcb92b20db88ebbcb26e0d32f414ca54a22/mkdocs_material-9.5.49.tar.gz", hash = "sha256:3671bb282b4f53a1c72e08adbe04d2481a98f85fed392530051f80ff94a9621d", size = 3949559, upload-time = "2024-12-16T10:25:10.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/2d/2dd23a36b48421db54f118bb6f6f733dbe2d5c78fe7867375e48649fd3df/mkdocs_material-9.5.49-py3-none-any.whl", hash = "sha256:c3c2d8176b18198435d3a3e119011922f3e11424074645c24019c2dcf08a360e", size = 8684098, upload-time = "2024-12-16T10:25:02.326Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "0.29.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/e8/d22922664a627a0d3d7ff4a6ca95800f5dde54f411982591b4621a76225d/mkdocstrings-0.29.1.tar.gz", hash = "sha256:8722f8f8c5cd75da56671e0a0c1bbed1df9946c0cef74794d6141b34011abd42", size = 1212686, upload-time = "2025-03-31T08:33:11.997Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/14/22533a578bf8b187e05d67e2c1721ce10e3f526610eebaf7a149d557ea7a/mkdocstrings-0.29.1-py3-none-any.whl", hash = "sha256:37a9736134934eea89cbd055a513d40a020d87dfcae9e3052c2a6b8cd4af09b6", size = 1631075, upload-time = "2025-03-31T08:33:09.661Z" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/ec/cb6debe2db77f1ef42b25b21d93b5021474de3037cd82385e586aee72545/mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3", size = 168207, upload-time = "2024-10-19T17:54:41.672Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/c1/ac524e1026d9580cbc654b5d19f5843c8b364a66d30f956372cd09fd2f92/mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a", size = 111759, upload-time = "2024-10-19T17:54:39.338Z" }, +] + +[[package]] +name = "mypy" +version = "1.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532, upload-time = "2024-10-22T21:55:47.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900, upload-time = "2024-10-22T21:55:37.103Z" }, + { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818, upload-time = "2024-10-22T21:55:11.513Z" }, + { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275, upload-time = "2024-10-22T21:54:37.694Z" }, + { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783, upload-time = "2024-10-22T21:55:42.852Z" }, + { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197, upload-time = "2024-10-22T21:54:43.68Z" }, + { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721, upload-time = "2024-10-22T21:54:22.321Z" }, + { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996, upload-time = "2024-10-22T21:54:46.023Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043, upload-time = "2024-10-22T21:55:06.231Z" }, + { url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996, upload-time = "2024-10-22T21:55:25.811Z" }, + { url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709, upload-time = "2024-10-22T21:55:21.246Z" }, + { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043, upload-time = "2024-10-22T21:55:16.617Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433, upload-time = "2023-02-04T12:11:27.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695, upload-time = "2023-02-04T12:11:25.002Z" }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + +[[package]] +name = "networkx" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, +] + +[[package]] +name = "numpy" +version = "1.26.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", size = 20335901, upload-time = "2024-02-05T23:55:32.801Z" }, + { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", size = 13685868, upload-time = "2024-02-05T23:55:56.28Z" }, + { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", size = 13925109, upload-time = "2024-02-05T23:56:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", size = 17950613, upload-time = "2024-02-05T23:56:56.054Z" }, + { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", size = 13572172, upload-time = "2024-02-05T23:57:21.56Z" }, + { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643, upload-time = "2024-02-05T23:57:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", size = 5677803, upload-time = "2024-02-05T23:58:08.963Z" }, + { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754, upload-time = "2024-02-05T23:58:36.364Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +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 = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "11.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707, upload-time = "2025-04-12T17:50:03.289Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185, upload-time = "2025-04-12T17:48:00.417Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306, upload-time = "2025-04-12T17:48:02.391Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121, upload-time = "2025-04-12T17:48:04.554Z" }, + { url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707, upload-time = "2025-04-12T17:48:06.831Z" }, + { url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921, upload-time = "2025-04-12T17:48:09.229Z" }, + { url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523, upload-time = "2025-04-12T17:48:11.631Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836, upload-time = "2025-04-12T17:48:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390, upload-time = "2025-04-12T17:48:15.938Z" }, + { url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309, upload-time = "2025-04-12T17:48:17.885Z" }, + { url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768, upload-time = "2025-04-12T17:48:19.655Z" }, + { url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087, upload-time = "2025-04-12T17:48:21.991Z" }, + { url = "https://files.pythonhosted.org/packages/36/9c/447528ee3776e7ab8897fe33697a7ff3f0475bb490c5ac1456a03dc57956/pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28", size = 3190098, upload-time = "2025-04-12T17:48:23.915Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/29d5cd052f7566a63e5b506fac9c60526e9ecc553825551333e1e18a4858/pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830", size = 3030166, upload-time = "2025-04-12T17:48:25.738Z" }, + { url = "https://files.pythonhosted.org/packages/71/5d/446ee132ad35e7600652133f9c2840b4799bbd8e4adba881284860da0a36/pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0", size = 4408674, upload-time = "2025-04-12T17:48:27.908Z" }, + { url = "https://files.pythonhosted.org/packages/69/5f/cbe509c0ddf91cc3a03bbacf40e5c2339c4912d16458fcb797bb47bcb269/pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1", size = 4496005, upload-time = "2025-04-12T17:48:29.888Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b3/dd4338d8fb8a5f312021f2977fb8198a1184893f9b00b02b75d565c33b51/pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f", size = 4518707, upload-time = "2025-04-12T17:48:31.874Z" }, + { url = "https://files.pythonhosted.org/packages/13/eb/2552ecebc0b887f539111c2cd241f538b8ff5891b8903dfe672e997529be/pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155", size = 4610008, upload-time = "2025-04-12T17:48:34.422Z" }, + { url = "https://files.pythonhosted.org/packages/72/d1/924ce51bea494cb6e7959522d69d7b1c7e74f6821d84c63c3dc430cbbf3b/pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14", size = 4585420, upload-time = "2025-04-12T17:48:37.641Z" }, + { url = "https://files.pythonhosted.org/packages/43/ab/8f81312d255d713b99ca37479a4cb4b0f48195e530cdc1611990eb8fd04b/pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b", size = 4667655, upload-time = "2025-04-12T17:48:39.652Z" }, + { url = "https://files.pythonhosted.org/packages/94/86/8f2e9d2dc3d308dfd137a07fe1cc478df0a23d42a6c4093b087e738e4827/pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2", size = 2332329, upload-time = "2025-04-12T17:48:41.765Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ec/1179083b8d6067a613e4d595359b5fdea65d0a3b7ad623fee906e1b3c4d2/pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691", size = 2676388, upload-time = "2025-04-12T17:48:43.625Z" }, + { url = "https://files.pythonhosted.org/packages/23/f1/2fc1e1e294de897df39fa8622d829b8828ddad938b0eaea256d65b84dd72/pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c", size = 2414950, upload-time = "2025-04-12T17:48:45.475Z" }, + { url = "https://files.pythonhosted.org/packages/c4/3e/c328c48b3f0ead7bab765a84b4977acb29f101d10e4ef57a5e3400447c03/pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22", size = 3192759, upload-time = "2025-04-12T17:48:47.866Z" }, + { url = "https://files.pythonhosted.org/packages/18/0e/1c68532d833fc8b9f404d3a642991441d9058eccd5606eab31617f29b6d4/pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7", size = 3033284, upload-time = "2025-04-12T17:48:50.189Z" }, + { url = "https://files.pythonhosted.org/packages/b7/cb/6faf3fb1e7705fd2db74e070f3bf6f88693601b0ed8e81049a8266de4754/pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16", size = 4445826, upload-time = "2025-04-12T17:48:52.346Z" }, + { url = "https://files.pythonhosted.org/packages/07/94/8be03d50b70ca47fb434a358919d6a8d6580f282bbb7af7e4aa40103461d/pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b", size = 4527329, upload-time = "2025-04-12T17:48:54.403Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a4/bfe78777076dc405e3bd2080bc32da5ab3945b5a25dc5d8acaa9de64a162/pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406", size = 4549049, upload-time = "2025-04-12T17:48:56.383Z" }, + { url = "https://files.pythonhosted.org/packages/65/4d/eaf9068dc687c24979e977ce5677e253624bd8b616b286f543f0c1b91662/pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91", size = 4635408, upload-time = "2025-04-12T17:48:58.782Z" }, + { url = "https://files.pythonhosted.org/packages/1d/26/0fd443365d9c63bc79feb219f97d935cd4b93af28353cba78d8e77b61719/pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751", size = 4614863, upload-time = "2025-04-12T17:49:00.709Z" }, + { url = "https://files.pythonhosted.org/packages/49/65/dca4d2506be482c2c6641cacdba5c602bc76d8ceb618fd37de855653a419/pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9", size = 4692938, upload-time = "2025-04-12T17:49:02.946Z" }, + { url = "https://files.pythonhosted.org/packages/b3/92/1ca0c3f09233bd7decf8f7105a1c4e3162fb9142128c74adad0fb361b7eb/pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd", size = 2335774, upload-time = "2025-04-12T17:49:04.889Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ac/77525347cb43b83ae905ffe257bbe2cc6fd23acb9796639a1f56aa59d191/pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e", size = 2681895, upload-time = "2025-04-12T17:49:06.635Z" }, + { url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234, upload-time = "2025-04-12T17:49:08.399Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/2d/7d512a3913d60623e7eb945c6d1b4f0bddf1d0b7ada5225274c87e5b53d1/platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351", size = 21291, upload-time = "2025-03-19T20:36:10.989Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/45/59578566b3275b8fd9157885918fcd0c4d74162928a5310926887b856a51/platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", size = 18499, upload-time = "2025-03-19T20:36:09.038Z" }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/c8/e22c292035f1bac8b9f5237a2622305bc0304e776080b246f3df57c4ff9f/pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", size = 191678, upload-time = "2024-10-08T16:09:37.641Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/8f/496e10d51edd6671ebe0432e33ff800aa86775d2d147ce7d43389324a525/pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878", size = 218713, upload-time = "2024-10-08T16:09:35.726Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.51" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" }, +] + +[[package]] +name = "psutil" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.15" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/92/a7296491dbf5585b3a987f3f3fc87af0e632121ff3e490c14b5f2d2b4eb5/pymdown_extensions-10.15.tar.gz", hash = "sha256:0e5994e32155f4b03504f939e501b981d306daf7ec2aa1cd2eb6bd300784f8f7", size = 852320, upload-time = "2025-04-27T23:48:29.183Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/d1/c54e608505776ce4e7966d03358ae635cfd51dff1da6ee421c090dbc797b/pymdown_extensions-10.15-py3-none-any.whl", hash = "sha256:46e99bb272612b0de3b7e7caf6da8dd5f4ca5212c0b273feb9304e236c484e5f", size = 265845, upload-time = "2025-04-27T23:48:27.359Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" }, +] + +[[package]] +name = "pytest" +version = "8.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919, upload-time = "2024-12-01T12:54:25.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083, upload-time = "2024-12-01T12:54:19.735Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pywin32" +version = "310" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, + { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, + { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, + { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, + { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631, upload-time = "2020-11-12T02:38:26.239Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911, upload-time = "2020-11-12T02:38:24.638Z" }, +] + +[[package]] +name = "pyzmq" +version = "26.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/11/b9213d25230ac18a71b39b3723494e57adebe36e066397b961657b3b41c1/pyzmq-26.4.0.tar.gz", hash = "sha256:4bd13f85f80962f91a651a7356fe0472791a5f7a92f227822b5acf44795c626d", size = 278293, upload-time = "2025-04-04T12:05:44.049Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/44/a778555ebfdf6c7fc00816aad12d185d10a74d975800341b1bc36bad1187/pyzmq-26.4.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:5227cb8da4b6f68acfd48d20c588197fd67745c278827d5238c707daf579227b", size = 1341586, upload-time = "2025-04-04T12:03:41.954Z" }, + { url = "https://files.pythonhosted.org/packages/9c/4f/f3a58dc69ac757e5103be3bd41fb78721a5e17da7cc617ddb56d973a365c/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1c07a7fa7f7ba86554a2b1bef198c9fed570c08ee062fd2fd6a4dcacd45f905", size = 665880, upload-time = "2025-04-04T12:03:43.45Z" }, + { url = "https://files.pythonhosted.org/packages/fe/45/50230bcfb3ae5cb98bee683b6edeba1919f2565d7cc1851d3c38e2260795/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae775fa83f52f52de73183f7ef5395186f7105d5ed65b1ae65ba27cb1260de2b", size = 902216, upload-time = "2025-04-04T12:03:45.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/59/56bbdc5689be5e13727491ad2ba5efd7cd564365750514f9bc8f212eef82/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66c760d0226ebd52f1e6b644a9e839b5db1e107a23f2fcd46ec0569a4fdd4e63", size = 859814, upload-time = "2025-04-04T12:03:47.188Z" }, + { url = "https://files.pythonhosted.org/packages/81/b1/57db58cfc8af592ce94f40649bd1804369c05b2190e4cbc0a2dad572baeb/pyzmq-26.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ef8c6ecc1d520debc147173eaa3765d53f06cd8dbe7bd377064cdbc53ab456f5", size = 855889, upload-time = "2025-04-04T12:03:49.223Z" }, + { url = "https://files.pythonhosted.org/packages/e8/92/47542e629cbac8f221c230a6d0f38dd3d9cff9f6f589ed45fdf572ffd726/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3150ef4084e163dec29ae667b10d96aad309b668fac6810c9e8c27cf543d6e0b", size = 1197153, upload-time = "2025-04-04T12:03:50.591Z" }, + { url = "https://files.pythonhosted.org/packages/07/e5/b10a979d1d565d54410afc87499b16c96b4a181af46e7645ab4831b1088c/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4448c9e55bf8329fa1dcedd32f661bf611214fa70c8e02fee4347bc589d39a84", size = 1507352, upload-time = "2025-04-04T12:03:52.473Z" }, + { url = "https://files.pythonhosted.org/packages/ab/58/5a23db84507ab9c01c04b1232a7a763be66e992aa2e66498521bbbc72a71/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e07dde3647afb084d985310d067a3efa6efad0621ee10826f2cb2f9a31b89d2f", size = 1406834, upload-time = "2025-04-04T12:03:54Z" }, + { url = "https://files.pythonhosted.org/packages/22/74/aaa837b331580c13b79ac39396601fb361454ee184ca85e8861914769b99/pyzmq-26.4.0-cp312-cp312-win32.whl", hash = "sha256:ba034a32ecf9af72adfa5ee383ad0fd4f4e38cdb62b13624278ef768fe5b5b44", size = 577992, upload-time = "2025-04-04T12:03:55.815Z" }, + { url = "https://files.pythonhosted.org/packages/30/0f/55f8c02c182856743b82dde46b2dc3e314edda7f1098c12a8227eeda0833/pyzmq-26.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:056a97aab4064f526ecb32f4343917a4022a5d9efb6b9df990ff72e1879e40be", size = 640466, upload-time = "2025-04-04T12:03:57.231Z" }, + { url = "https://files.pythonhosted.org/packages/e4/29/073779afc3ef6f830b8de95026ef20b2d1ec22d0324d767748d806e57379/pyzmq-26.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f23c750e485ce1eb639dbd576d27d168595908aa2d60b149e2d9e34c9df40e0", size = 556342, upload-time = "2025-04-04T12:03:59.218Z" }, + { url = "https://files.pythonhosted.org/packages/d7/20/fb2c92542488db70f833b92893769a569458311a76474bda89dc4264bd18/pyzmq-26.4.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:c43fac689880f5174d6fc864857d1247fe5cfa22b09ed058a344ca92bf5301e3", size = 1339484, upload-time = "2025-04-04T12:04:00.671Z" }, + { url = "https://files.pythonhosted.org/packages/58/29/2f06b9cabda3a6ea2c10f43e67ded3e47fc25c54822e2506dfb8325155d4/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:902aca7eba477657c5fb81c808318460328758e8367ecdd1964b6330c73cae43", size = 666106, upload-time = "2025-04-04T12:04:02.366Z" }, + { url = "https://files.pythonhosted.org/packages/77/e4/dcf62bd29e5e190bd21bfccaa4f3386e01bf40d948c239239c2f1e726729/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e48a830bfd152fe17fbdeaf99ac5271aa4122521bf0d275b6b24e52ef35eb6", size = 902056, upload-time = "2025-04-04T12:04:03.919Z" }, + { url = "https://files.pythonhosted.org/packages/1a/cf/b36b3d7aea236087d20189bec1a87eeb2b66009731d7055e5c65f845cdba/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31be2b6de98c824c06f5574331f805707c667dc8f60cb18580b7de078479891e", size = 860148, upload-time = "2025-04-04T12:04:05.581Z" }, + { url = "https://files.pythonhosted.org/packages/18/a6/f048826bc87528c208e90604c3bf573801e54bd91e390cbd2dfa860e82dc/pyzmq-26.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6332452034be001bbf3206ac59c0d2a7713de5f25bb38b06519fc6967b7cf771", size = 855983, upload-time = "2025-04-04T12:04:07.096Z" }, + { url = "https://files.pythonhosted.org/packages/0a/27/454d34ab6a1d9772a36add22f17f6b85baf7c16e14325fa29e7202ca8ee8/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:da8c0f5dd352136853e6a09b1b986ee5278dfddfebd30515e16eae425c872b30", size = 1197274, upload-time = "2025-04-04T12:04:08.523Z" }, + { url = "https://files.pythonhosted.org/packages/f4/3d/7abfeab6b83ad38aa34cbd57c6fc29752c391e3954fd12848bd8d2ec0df6/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f4ccc1a0a2c9806dda2a2dd118a3b7b681e448f3bb354056cad44a65169f6d86", size = 1507120, upload-time = "2025-04-04T12:04:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/13/ff/bc8d21dbb9bc8705126e875438a1969c4f77e03fc8565d6901c7933a3d01/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1c0b5fceadbab461578daf8d1dcc918ebe7ddd2952f748cf30c7cf2de5d51101", size = 1406738, upload-time = "2025-04-04T12:04:12.509Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5d/d4cd85b24de71d84d81229e3bbb13392b2698432cf8fdcea5afda253d587/pyzmq-26.4.0-cp313-cp313-win32.whl", hash = "sha256:28e2b0ff5ba4b3dd11062d905682bad33385cfa3cc03e81abd7f0822263e6637", size = 577826, upload-time = "2025-04-04T12:04:14.289Z" }, + { url = "https://files.pythonhosted.org/packages/c6/6c/f289c1789d7bb6e5a3b3bef7b2a55089b8561d17132be7d960d3ff33b14e/pyzmq-26.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b", size = 640406, upload-time = "2025-04-04T12:04:15.757Z" }, + { url = "https://files.pythonhosted.org/packages/b3/99/676b8851cb955eb5236a0c1e9ec679ea5ede092bf8bf2c8a68d7e965cac3/pyzmq-26.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:1edb0385c7f025045d6e0f759d4d3afe43c17a3d898914ec6582e6f464203c08", size = 556216, upload-time = "2025-04-04T12:04:17.212Z" }, + { url = "https://files.pythonhosted.org/packages/65/c2/1fac340de9d7df71efc59d9c50fc7a635a77b103392d1842898dd023afcb/pyzmq-26.4.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:93a29e882b2ba1db86ba5dd5e88e18e0ac6b627026c5cfbec9983422011b82d4", size = 1333769, upload-time = "2025-04-04T12:04:18.665Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c7/6c03637e8d742c3b00bec4f5e4cd9d1c01b2f3694c6f140742e93ca637ed/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45684f276f57110bb89e4300c00f1233ca631f08f5f42528a5c408a79efc4a", size = 658826, upload-time = "2025-04-04T12:04:20.405Z" }, + { url = "https://files.pythonhosted.org/packages/a5/97/a8dca65913c0f78e0545af2bb5078aebfc142ca7d91cdaffa1fbc73e5dbd/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f72073e75260cb301aad4258ad6150fa7f57c719b3f498cb91e31df16784d89b", size = 891650, upload-time = "2025-04-04T12:04:22.413Z" }, + { url = "https://files.pythonhosted.org/packages/7d/7e/f63af1031eb060bf02d033732b910fe48548dcfdbe9c785e9f74a6cc6ae4/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be37e24b13026cfedd233bcbbccd8c0bcd2fdd186216094d095f60076201538d", size = 849776, upload-time = "2025-04-04T12:04:23.959Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fa/1a009ce582802a895c0d5fe9413f029c940a0a8ee828657a3bb0acffd88b/pyzmq-26.4.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:237b283044934d26f1eeff4075f751b05d2f3ed42a257fc44386d00df6a270cf", size = 842516, upload-time = "2025-04-04T12:04:25.449Z" }, + { url = "https://files.pythonhosted.org/packages/6e/bc/f88b0bad0f7a7f500547d71e99f10336f2314e525d4ebf576a1ea4a1d903/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:b30f862f6768b17040929a68432c8a8be77780317f45a353cb17e423127d250c", size = 1189183, upload-time = "2025-04-04T12:04:27.035Z" }, + { url = "https://files.pythonhosted.org/packages/d9/8c/db446a3dd9cf894406dec2e61eeffaa3c07c3abb783deaebb9812c4af6a5/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:c80fcd3504232f13617c6ab501124d373e4895424e65de8b72042333316f64a8", size = 1495501, upload-time = "2025-04-04T12:04:28.833Z" }, + { url = "https://files.pythonhosted.org/packages/05/4c/bf3cad0d64c3214ac881299c4562b815f05d503bccc513e3fd4fdc6f67e4/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:26a2a7451606b87f67cdeca2c2789d86f605da08b4bd616b1a9981605ca3a364", size = 1395540, upload-time = "2025-04-04T12:04:30.562Z" }, +] + +[[package]] +name = "rdkit" +version = "2023.9.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/01/306ecb02edea5f190182e440cec570a35cf9e86decc980dfc335279c3416/rdkit-2023.9.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1dbe6142f4580e264697825adf885eb1848acfd72d059d162d8bf5c220f12d98", size = 28225396, upload-time = "2023-12-22T15:47:02.412Z" }, + { url = "https://files.pythonhosted.org/packages/26/c2/87ba5b7e412e3a7aeff9896dbc5d65b82dc178d787c35bd7b63a1b1ff50e/rdkit-2023.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7e21078210f07e01733b9c15644ea340d774d89e9f4290a6579ea8c177d72b46", size = 26977940, upload-time = "2023-12-22T15:47:07.515Z" }, + { url = "https://files.pythonhosted.org/packages/8f/50/eab009e4ebde3515c205f898fe98501a844bbce4dcd4f7f7b92801615a8f/rdkit-2023.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0440d546673c1828839eb8b627bcdd09ed9a0d2aa5cebf34e135df14aaa3838f", size = 33404609, upload-time = "2023-12-22T15:47:12.099Z" }, + { url = "https://files.pythonhosted.org/packages/03/b6/278a17c6e2f89132f23da8e7ef87cfb2263da48ce807a08789b23b6808f7/rdkit-2023.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8d57bb7178427bdf43d92cfb962d76331d6d12cb71c5bba283abbf47d7f7f3b", size = 34215688, upload-time = "2023-12-22T15:47:17.93Z" }, + { url = "https://files.pythonhosted.org/packages/a2/63/a164a042b6c6f6e753d1250f4f7d9762c4d8ffa41e97d31c1272454f51f4/rdkit-2023.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:ac410c68415d4f1f6587e7edba49e272a798c871fc9d98cc323fc196f1c2c41f", size = 21012337, upload-time = "2023-12-22T15:47:23.928Z" }, +] + +[[package]] +name = "regex" +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, + { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, + { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, + { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, + { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, + { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, + { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, + { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, + { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, + { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, + { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, + { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, + { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, + { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, +] + +[[package]] +name = "ruff" +version = "0.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/fd/37b826d297b29f8ed049f9739e111d0b8eb5268e47efc0f19462fb977b90/ruff-0.4.7.tar.gz", hash = "sha256:2331d2b051dc77a289a653fcc6a42cce357087c5975738157cd966590b18b5e1", size = 2549974, upload-time = "2024-05-31T20:44:17.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/e4/3274746201eb4d31f5846a07d40795eae0e5b6aeae8965a99b26af585a56/ruff-0.4.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e089371c67892a73b6bb1525608e89a2aca1b77b5440acf7a71dda5dac958f9e", size = 8556935, upload-time = "2024-05-31T20:42:32.79Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d3/023af8521e45d171746f5715dd98946fa5fbe24c4e99fe3f3ae689335224/ruff-0.4.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:10f973d521d910e5f9c72ab27e409e839089f955be8a4c8826601a6323a89753", size = 8186671, upload-time = "2024-05-31T20:42:47.352Z" }, + { url = "https://files.pythonhosted.org/packages/77/5b/46d3ffefafa5d7436352d1ca918122fe290c3cfbcb53c34aa67d338b3ac2/ruff-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c3d110970001dfa494bcd95478e62286c751126dfb15c3c46e7915fc49694f", size = 8208662, upload-time = "2024-05-31T20:42:57.318Z" }, + { url = "https://files.pythonhosted.org/packages/9c/9e/e59f95cb81ee84a47c143a630063030e2369d267cd118f76c06e5e209168/ruff-0.4.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa9773c6c00f4958f73b317bc0fd125295110c3776089f6ef318f4b775f0abe4", size = 7597653, upload-time = "2024-05-31T20:43:07.341Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ed/e406117d88178b970eb1f363d9dd81d39e685be516fd65e722e3e37e76b0/ruff-0.4.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07fc80bbb61e42b3b23b10fda6a2a0f5a067f810180a3760c5ef1b456c21b9db", size = 8776122, upload-time = "2024-05-31T20:43:26.233Z" }, + { url = "https://files.pythonhosted.org/packages/5d/77/e83c88d806be0bc57b9b376bb021cf154466127e382d39cb0efeb62e3f29/ruff-0.4.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fa4dafe3fe66d90e2e2b63fa1591dd6e3f090ca2128daa0be33db894e6c18648", size = 9501274, upload-time = "2024-05-31T20:43:33.991Z" }, + { url = "https://files.pythonhosted.org/packages/7b/55/242f0cf3db7aacf8dcb402a25f901353f4f6f5f8c5e04542c64cfcb9b42c/ruff-0.4.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7c0083febdec17571455903b184a10026603a1de078428ba155e7ce9358c5f6", size = 9081583, upload-time = "2024-05-31T20:43:42.299Z" }, + { url = "https://files.pythonhosted.org/packages/f4/01/54943fc17f4c3ebb256fd5ad5b2b6d19fb0676ee12968da91db6cf2409ff/ruff-0.4.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad1b20e66a44057c326168437d680a2166c177c939346b19c0d6b08a62a37589", size = 10205224, upload-time = "2024-05-31T20:43:45.832Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/e8a251c07e67ef4f760e473ec612e42502a83f294fe44aca3aafb4e08f8b/ruff-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf5d818553add7511c38b05532d94a407f499d1a76ebb0cad0374e32bc67202", size = 8803303, upload-time = "2024-05-31T20:43:49.509Z" }, + { url = "https://files.pythonhosted.org/packages/58/a4/6a2ece523f1d3ccd125b5f1db38a11fcaa252cc452d4c582e4cc27293ec6/ruff-0.4.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50e9651578b629baec3d1513b2534de0ac7ed7753e1382272b8d609997e27e83", size = 8116589, upload-time = "2024-05-31T20:43:52.933Z" }, + { url = "https://files.pythonhosted.org/packages/0f/77/3ad58c9fb2ea6390e2d29c3595119d86ac6fda8187f16e1e5b5066220c2e/ruff-0.4.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8874a9df7766cb956b218a0a239e0a5d23d9e843e4da1e113ae1d27ee420877a", size = 7589687, upload-time = "2024-05-31T20:43:56.301Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d3/f9b2eb5f633790508e203f4d6574c23e3161d0fff4ca0bfe9da19e3e6e8c/ruff-0.4.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b9de9a6e49f7d529decd09381c0860c3f82fa0b0ea00ea78409b785d2308a567", size = 8379595, upload-time = "2024-05-31T20:43:59.182Z" }, + { url = "https://files.pythonhosted.org/packages/55/db/d8d9a8f582ae0ea81181131ff8d092a5fb3e7e4b4781f4ddd51f0793bf4f/ruff-0.4.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:13a1768b0691619822ae6d446132dbdfd568b700ecd3652b20d4e8bc1e498f78", size = 8858060, upload-time = "2024-05-31T20:44:02.33Z" }, + { url = "https://files.pythonhosted.org/packages/2f/57/9e7a6bc709063936d0c2b7ce20ee38c16adaab38034b1a5e80b71ec3f950/ruff-0.4.7-py3-none-win32.whl", hash = "sha256:769e5a51df61e07e887b81e6f039e7ed3573316ab7dd9f635c5afaa310e4030e", size = 7826212, upload-time = "2024-05-31T20:44:06.819Z" }, + { url = "https://files.pythonhosted.org/packages/3b/86/278330ead9f978549130e582457d2a6edfaf0577d463bd589ed8cf9f084e/ruff-0.4.7-py3-none-win_amd64.whl", hash = "sha256:9e3ab684ad403a9ed1226894c32c3ab9c2e0718440f6f50c7c5829932bc9e054", size = 8609712, upload-time = "2024-05-31T20:44:09.567Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e4/174f07c5622df74cc8917b7c3c5eac92ca063e7728e95048010b7314e9df/ruff-0.4.7-py3-none-win_arm64.whl", hash = "sha256:10f2204b9a613988e3484194c2c9e96a22079206b22b787605c255f130db5ed7", size = 7993707, upload-time = "2024-05-31T20:44:13.636Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762, upload-time = "2024-11-27T22:38:07.731Z" }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453, upload-time = "2024-11-27T22:38:09.384Z" }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486, upload-time = "2024-11-27T22:38:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349, upload-time = "2024-11-27T22:38:11.443Z" }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159, upload-time = "2024-11-27T22:38:13.099Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243, upload-time = "2024-11-27T22:38:14.766Z" }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645, upload-time = "2024-11-27T22:38:15.843Z" }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584, upload-time = "2024-11-27T22:38:17.645Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875, upload-time = "2024-11-27T22:38:19.159Z" }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418, upload-time = "2024-11-27T22:38:20.064Z" }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708, upload-time = "2024-11-27T22:38:21.659Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582, upload-time = "2024-11-27T22:38:22.693Z" }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543, upload-time = "2024-11-27T22:38:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691, upload-time = "2024-11-27T22:38:26.081Z" }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170, upload-time = "2024-11-27T22:38:27.921Z" }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530, upload-time = "2024-11-27T22:38:29.591Z" }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666, upload-time = "2024-11-27T22:38:30.639Z" }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954, upload-time = "2024-11-27T22:38:31.702Z" }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724, upload-time = "2024-11-27T22:38:32.837Z" }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383, upload-time = "2024-11-27T22:38:34.455Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, +] + +[[package]] +name = "tornado" +version = "6.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/59/45/a0daf161f7d6f36c3ea5fc0c2de619746cc3dd4c76402e9db545bd920f63/tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", size = 501135, upload-time = "2024-11-22T03:06:38.036Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/7e/71f604d8cea1b58f82ba3590290b66da1e72d840aeb37e0d5f7291bd30db/tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1", size = 436299, upload-time = "2024-11-22T03:06:20.162Z" }, + { url = "https://files.pythonhosted.org/packages/96/44/87543a3b99016d0bf54fdaab30d24bf0af2e848f1d13d34a3a5380aabe16/tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", size = 434253, upload-time = "2024-11-22T03:06:22.39Z" }, + { url = "https://files.pythonhosted.org/packages/cb/fb/fdf679b4ce51bcb7210801ef4f11fdac96e9885daa402861751353beea6e/tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", size = 437602, upload-time = "2024-11-22T03:06:24.214Z" }, + { url = "https://files.pythonhosted.org/packages/4f/3b/e31aeffffc22b475a64dbeb273026a21b5b566f74dee48742817626c47dc/tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", size = 436972, upload-time = "2024-11-22T03:06:25.559Z" }, + { url = "https://files.pythonhosted.org/packages/22/55/b78a464de78051a30599ceb6983b01d8f732e6f69bf37b4ed07f642ac0fc/tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", size = 437173, upload-time = "2024-11-22T03:06:27.584Z" }, + { url = "https://files.pythonhosted.org/packages/79/5e/be4fb0d1684eb822c9a62fb18a3e44a06188f78aa466b2ad991d2ee31104/tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", size = 437892, upload-time = "2024-11-22T03:06:28.933Z" }, + { url = "https://files.pythonhosted.org/packages/f5/33/4f91fdd94ea36e1d796147003b490fe60a0215ac5737b6f9c65e160d4fe0/tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", size = 437334, upload-time = "2024-11-22T03:06:30.428Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ae/c1b22d4524b0e10da2f29a176fb2890386f7bd1f63aacf186444873a88a0/tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", size = 437261, upload-time = "2024-11-22T03:06:32.458Z" }, + { url = "https://files.pythonhosted.org/packages/b5/25/36dbd49ab6d179bcfc4c6c093a51795a4f3bed380543a8242ac3517a1751/tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", size = 438463, upload-time = "2024-11-22T03:06:34.71Z" }, + { url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907, upload-time = "2024-11-22T03:06:36.71Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" }, +] + +[[package]] +name = "urllib3" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.30.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/e0/633e369b91bbc664df47dcb5454b6c7cf441e8f5b9d0c250ce9f0546401e/virtualenv-20.30.0.tar.gz", hash = "sha256:800863162bcaa5450a6e4d721049730e7f2dae07720e0902b0e4040bd6f9ada8", size = 4346945, upload-time = "2025-03-31T16:33:29.185Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/ed/3cfeb48175f0671ec430ede81f628f9fb2b1084c9064ca67ebe8c0ed6a05/virtualenv-20.30.0-py3-none-any.whl", hash = "sha256:e34302959180fca3af42d1800df014b35019490b119eba981af27f2fa486e5d6", size = 4329461, upload-time = "2025-03-31T16:33:26.758Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, +] + +[[package]] +name = "widgetsnbextension" +version = "4.0.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/53/2e0253c5efd69c9656b1843892052a31c36d37ad42812b5da45c62191f7e/widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af", size = 1097428, upload-time = "2025-04-10T13:01:25.628Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503, upload-time = "2025-04-10T13:01:23.086Z" }, +] From 452cdc6f6fcc139e1f5a082d5b7f82481a9c5769 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:33:00 -0400 Subject: [PATCH 10/24] DEV: move typing to parent --- src/fragmentretro/app/gui/controller.py | 2 +- src/fragmentretro/app/gui/state.py | 2 +- src/fragmentretro/fragmenter.py | 2 +- src/fragmentretro/retrosynthesis.py | 8 ++++---- src/fragmentretro/solutions.py | 2 +- src/fragmentretro/substructure_matcher.py | 2 +- .../{utils/type_definitions.py => typing.py} | 0 7 files changed, 9 insertions(+), 9 deletions(-) rename src/fragmentretro/{utils/type_definitions.py => typing.py} (100%) diff --git a/src/fragmentretro/app/gui/controller.py b/src/fragmentretro/app/gui/controller.py index fe71ef1..3fd1356 100644 --- a/src/fragmentretro/app/gui/controller.py +++ b/src/fragmentretro/app/gui/controller.py @@ -37,8 +37,8 @@ from fragmentretro.fragmenter_base import Fragmenter from fragmentretro.retrosynthesis import Retrosynthesis from fragmentretro.solutions import RetrosynthesisSolution +from fragmentretro.typing import CombType, SolutionType from fragmentretro.utils.helpers import sort_by_heavy_atoms -from fragmentretro.utils.type_definitions import CombType, SolutionType class GuiController: diff --git a/src/fragmentretro/app/gui/state.py b/src/fragmentretro/app/gui/state.py index d0b295b..f8c35b6 100644 --- a/src/fragmentretro/app/gui/state.py +++ b/src/fragmentretro/app/gui/state.py @@ -2,7 +2,7 @@ from fragmentretro.retrosynthesis import Retrosynthesis from fragmentretro.solutions import RetrosynthesisSolution -from fragmentretro.utils.type_definitions import CombType, SolutionType +from fragmentretro.typing import CombType, SolutionType class AppState: diff --git a/src/fragmentretro/fragmenter.py b/src/fragmentretro/fragmenter.py index 31a4f3b..a785a59 100644 --- a/src/fragmentretro/fragmenter.py +++ b/src/fragmentretro/fragmenter.py @@ -5,7 +5,7 @@ from fragmentretro.fragmentation.r_brics import break_r_brics_bonds, find_brics_bonds from fragmentretro.fragmenter_base import Fragmenter -from fragmentretro.utils.type_definitions import BondType +from fragmentretro.typing import BondType class BRICSFragmenter(Fragmenter): diff --git a/src/fragmentretro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py index de65679..ce1e2a9 100644 --- a/src/fragmentretro/retrosynthesis.py +++ b/src/fragmentretro/retrosynthesis.py @@ -3,10 +3,7 @@ from fragmentretro.fragmenter_base import Fragmenter from fragmentretro.substructure_matcher import SubstructureMatcher -from fragmentretro.utils.filter_compound import CompoundFilter -from fragmentretro.utils.helpers import remove_indices_before_dummy -from fragmentretro.utils.logging_config import logger -from fragmentretro.utils.type_definitions import ( +from fragmentretro.typing import ( BBsType, CombBBsDictType, CombFilterIndicesDictType, @@ -15,6 +12,9 @@ FragmentBBsDictType, StageCombDictType, ) +from fragmentretro.utils.filter_compound import CompoundFilter +from fragmentretro.utils.helpers import remove_indices_before_dummy +from fragmentretro.utils.logging_config import logger class Retrosynthesis: diff --git a/src/fragmentretro/solutions.py b/src/fragmentretro/solutions.py index 1899406..fbd0f13 100644 --- a/src/fragmentretro/solutions.py +++ b/src/fragmentretro/solutions.py @@ -5,8 +5,8 @@ from rdkit.Chem import Draw from fragmentretro.retrosynthesis import Retrosynthesis +from fragmentretro.typing import CombType, SolutionType from fragmentretro.utils.logging_config import logger -from fragmentretro.utils.type_definitions import CombType, SolutionType class RetrosynthesisSolution: diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index e831478..4662087 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -5,8 +5,8 @@ from rdkit import Chem from rdkit.Chem.rdchem import Atom +from fragmentretro.typing import BBsType from fragmentretro.utils.logging_config import logger -from fragmentretro.utils.type_definitions import BBsType class SubstructureMatcher: diff --git a/src/fragmentretro/utils/type_definitions.py b/src/fragmentretro/typing.py similarity index 100% rename from src/fragmentretro/utils/type_definitions.py rename to src/fragmentretro/typing.py From 6f09215f8e263fc2ec02c42d89c29a84eb3324ae Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:35:49 -0400 Subject: [PATCH 11/24] GIT: update qual workflow to drop isort --- .github/workflows/quality.yml | 14 ++++---------- .gitignore | 2 ++ src/fragmentretro/fragmenter_base.py | 2 +- src/fragmentretro/utils/filter_compound.py | 6 +++--- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 9b0eae5..59117a2 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -3,17 +3,17 @@ name: Code Quality on: [push, pull_request] jobs: - qualitycheck: + lint: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Set up Python 3.11 + - name: Set up Python 3.12 uses: actions/setup-python@v4 with: - python-version: '3.11' + python-version: '3.12' - name: Install uv run: | @@ -45,11 +45,5 @@ jobs: - name: Run ruff (formatter) run: ruff format --check - - name: Run isort - run: isort --check --profile black . - - name: Run mypy - run: mypy . - - - name: Run tests - run: pytest -v \ No newline at end of file + run: mypy . \ No newline at end of file diff --git a/.gitignore b/.gitignore index e6971dd..54b8344 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ wheels/ *.egg-info/ .installed.cfg *.egg +.mypy_cache/ +.ruff_cache/ # Virtual Environment .venv/ diff --git a/src/fragmentretro/fragmenter_base.py b/src/fragmentretro/fragmenter_base.py index 7be11bf..7b0dc65 100644 --- a/src/fragmentretro/fragmenter_base.py +++ b/src/fragmentretro/fragmenter_base.py @@ -7,8 +7,8 @@ from rdkit import Chem from rdkit.Chem import Mol +from fragmentretro.typing import AtomMappingType, BondType, CombType from fragmentretro.utils.logging_config import logger -from fragmentretro.utils.type_definitions import AtomMappingType, BondType, CombType class Fragmenter(ABC): diff --git a/src/fragmentretro/utils/filter_compound.py b/src/fragmentretro/utils/filter_compound.py index b5a97af..ddf3c58 100644 --- a/src/fragmentretro/utils/filter_compound.py +++ b/src/fragmentretro/utils/filter_compound.py @@ -6,13 +6,13 @@ from rdkit.Chem import rdMolDescriptors from tqdm import tqdm -from fragmentretro.utils.helpers import canonicalize_smiles, replace_dummy_atoms_regex -from fragmentretro.utils.logging_config import logger -from fragmentretro.utils.type_definitions import ( +from fragmentretro.typing import ( BBsType, FilterIndicesType, MolProperties, ) +from fragmentretro.utils.helpers import canonicalize_smiles, replace_dummy_atoms_regex +from fragmentretro.utils.logging_config import logger def get_mol_properties(smiles: str, fpSize: int = 2048) -> MolProperties: From c53d08e9d4a41d507eaa1cb4f6cf1bb4c9c29f67 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:40:46 -0400 Subject: [PATCH 12/24] DEV: update local ruff --- data/process_buyables.py | 3 +- pyproject.toml | 8 +-- scripts/paroutes_example.py | 3 +- src/fragmentretro/fragmenter_base.py | 4 +- uv.lock | 89 ++++++++++++++-------------- 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/data/process_buyables.py b/data/process_buyables.py index dd37267..1837e9b 100644 --- a/data/process_buyables.py +++ b/data/process_buyables.py @@ -3,10 +3,11 @@ import shutil from pathlib import Path +from tqdm import tqdm + from fragmentretro.utils.filter_compound import precompute_properties from fragmentretro.utils.helpers import canonicalize_smiles from fragmentretro.utils.logging_config import logger -from tqdm import tqdm DATA_PATH = Path(__file__).parent BUYABLES_PATH = DATA_PATH / "buyables" diff --git a/pyproject.toml b/pyproject.toml index 1d37579..1dc5e11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,11 +35,11 @@ dev = [ "mkdocs==1.6.1", "mkdocstrings-python==1.12.2", "mkdocs-material==9.5.49", - "pytest==8.3.4", - "ruff>=0.4.7", - "mypy==1.13.0", "mypy-extensions==1.0.0", - "pre-commit==4.0.1", + "ruff>=0.11.8", + "mypy>=1.15.0", + "pre-commit>=4.2.0", + "pytest>=8.3.5", ] [tool.mypy] diff --git a/scripts/paroutes_example.py b/scripts/paroutes_example.py index 370dd41..e0d0e62 100644 --- a/scripts/paroutes_example.py +++ b/scripts/paroutes_example.py @@ -1,11 +1,12 @@ import pickle from pathlib import Path +from tqdm import tqdm + from fragmentretro.fragmenter import BRICSFragmenter # or use rBRICSFragmenter from fragmentretro.retrosynthesis import Retrosynthesis from fragmentretro.solutions import RetrosynthesisSolution from fragmentretro.utils.logging_config import logger -from tqdm import tqdm DATA_PATH = Path(__name__).parent / "data" PAROUTES_PATH = DATA_PATH / "paroutes" diff --git a/src/fragmentretro/fragmenter_base.py b/src/fragmentretro/fragmenter_base.py index 7b0dc65..bec1a50 100644 --- a/src/fragmentretro/fragmenter_base.py +++ b/src/fragmentretro/fragmenter_base.py @@ -215,9 +215,7 @@ def check_connected_subgraph(self, combination: CombType) -> bool: """ # check if the combination is a connected subgraph subgraph = self.fragment_graph.subgraph(combination) - if not nx.is_connected(subgraph): - return False - return True + return nx.is_connected(subgraph) def get_combination_smiles(self, combination: CombType) -> str: """ diff --git a/uv.lock b/uv.lock index 6594a2d..b4822ba 100644 --- a/uv.lock +++ b/uv.lock @@ -312,14 +312,14 @@ requires-dist = [ { name = "mkdocs", marker = "extra == 'dev'", specifier = "==1.6.1" }, { name = "mkdocs-material", marker = "extra == 'dev'", specifier = "==9.5.49" }, { name = "mkdocstrings-python", marker = "extra == 'dev'", specifier = "==1.12.2" }, - { name = "mypy", marker = "extra == 'dev'", specifier = "==1.13.0" }, + { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.15.0" }, { name = "mypy-extensions", marker = "extra == 'dev'", specifier = "==1.0.0" }, { name = "networkx", specifier = "==3.4.2" }, { name = "numpy", specifier = "==1.26.4" }, - { name = "pre-commit", marker = "extra == 'dev'", specifier = "==4.0.1" }, - { name = "pytest", marker = "extra == 'dev'", specifier = "==8.3.4" }, + { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=4.2.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.5" }, { name = "rdkit", specifier = "==2023.9.3" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.4.7" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.11.8" }, { name = "tomli", specifier = ">=2.2.1" }, { name = "tqdm", specifier = "==4.67.1" }, { name = "typing-extensions", specifier = "==4.12.2" }, @@ -785,25 +785,27 @@ wheels = [ [[package]] name = "mypy" -version = "1.13.0" +version = "1.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532, upload-time = "2024-10-22T21:55:47.458Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717, upload-time = "2025-02-05T03:50:34.655Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900, upload-time = "2024-10-22T21:55:37.103Z" }, - { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818, upload-time = "2024-10-22T21:55:11.513Z" }, - { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275, upload-time = "2024-10-22T21:54:37.694Z" }, - { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783, upload-time = "2024-10-22T21:55:42.852Z" }, - { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197, upload-time = "2024-10-22T21:54:43.68Z" }, - { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721, upload-time = "2024-10-22T21:54:22.321Z" }, - { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996, upload-time = "2024-10-22T21:54:46.023Z" }, - { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043, upload-time = "2024-10-22T21:55:06.231Z" }, - { url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996, upload-time = "2024-10-22T21:55:25.811Z" }, - { url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709, upload-time = "2024-10-22T21:55:21.246Z" }, - { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043, upload-time = "2024-10-22T21:55:16.617Z" }, + { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981, upload-time = "2025-02-05T03:50:28.25Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175, upload-time = "2025-02-05T03:50:13.411Z" }, + { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675, upload-time = "2025-02-05T03:50:31.421Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020, upload-time = "2025-02-05T03:48:48.705Z" }, + { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582, upload-time = "2025-02-05T03:49:03.628Z" }, + { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614, upload-time = "2025-02-05T03:50:00.313Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592, upload-time = "2025-02-05T03:48:55.789Z" }, + { url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611, upload-time = "2025-02-05T03:48:44.581Z" }, + { url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443, upload-time = "2025-02-05T03:49:25.514Z" }, + { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541, upload-time = "2025-02-05T03:49:57.623Z" }, + { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348, upload-time = "2025-02-05T03:48:52.361Z" }, + { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648, upload-time = "2025-02-05T03:49:11.395Z" }, + { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777, upload-time = "2025-02-05T03:50:08.348Z" }, ] [[package]] @@ -967,7 +969,7 @@ wheels = [ [[package]] name = "pre-commit" -version = "4.0.1" +version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -976,9 +978,9 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/c8/e22c292035f1bac8b9f5237a2622305bc0304e776080b246f3df57c4ff9f/pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", size = 191678, upload-time = "2024-10-08T16:09:37.641Z" } +sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/8f/496e10d51edd6671ebe0432e33ff800aa86775d2d147ce7d43389324a525/pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878", size = 218713, upload-time = "2024-10-08T16:09:35.726Z" }, + { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, ] [[package]] @@ -1068,7 +1070,7 @@ wheels = [ [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1076,9 +1078,9 @@ dependencies = [ { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919, upload-time = "2024-12-01T12:54:25.98Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083, upload-time = "2024-12-01T12:54:19.735Z" }, + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, ] [[package]] @@ -1256,26 +1258,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.4.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/fd/37b826d297b29f8ed049f9739e111d0b8eb5268e47efc0f19462fb977b90/ruff-0.4.7.tar.gz", hash = "sha256:2331d2b051dc77a289a653fcc6a42cce357087c5975738157cd966590b18b5e1", size = 2549974, upload-time = "2024-05-31T20:44:17.441Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/e4/3274746201eb4d31f5846a07d40795eae0e5b6aeae8965a99b26af585a56/ruff-0.4.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e089371c67892a73b6bb1525608e89a2aca1b77b5440acf7a71dda5dac958f9e", size = 8556935, upload-time = "2024-05-31T20:42:32.79Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d3/023af8521e45d171746f5715dd98946fa5fbe24c4e99fe3f3ae689335224/ruff-0.4.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:10f973d521d910e5f9c72ab27e409e839089f955be8a4c8826601a6323a89753", size = 8186671, upload-time = "2024-05-31T20:42:47.352Z" }, - { url = "https://files.pythonhosted.org/packages/77/5b/46d3ffefafa5d7436352d1ca918122fe290c3cfbcb53c34aa67d338b3ac2/ruff-0.4.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c3d110970001dfa494bcd95478e62286c751126dfb15c3c46e7915fc49694f", size = 8208662, upload-time = "2024-05-31T20:42:57.318Z" }, - { url = "https://files.pythonhosted.org/packages/9c/9e/e59f95cb81ee84a47c143a630063030e2369d267cd118f76c06e5e209168/ruff-0.4.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa9773c6c00f4958f73b317bc0fd125295110c3776089f6ef318f4b775f0abe4", size = 7597653, upload-time = "2024-05-31T20:43:07.341Z" }, - { url = "https://files.pythonhosted.org/packages/7b/ed/e406117d88178b970eb1f363d9dd81d39e685be516fd65e722e3e37e76b0/ruff-0.4.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07fc80bbb61e42b3b23b10fda6a2a0f5a067f810180a3760c5ef1b456c21b9db", size = 8776122, upload-time = "2024-05-31T20:43:26.233Z" }, - { url = "https://files.pythonhosted.org/packages/5d/77/e83c88d806be0bc57b9b376bb021cf154466127e382d39cb0efeb62e3f29/ruff-0.4.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fa4dafe3fe66d90e2e2b63fa1591dd6e3f090ca2128daa0be33db894e6c18648", size = 9501274, upload-time = "2024-05-31T20:43:33.991Z" }, - { url = "https://files.pythonhosted.org/packages/7b/55/242f0cf3db7aacf8dcb402a25f901353f4f6f5f8c5e04542c64cfcb9b42c/ruff-0.4.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7c0083febdec17571455903b184a10026603a1de078428ba155e7ce9358c5f6", size = 9081583, upload-time = "2024-05-31T20:43:42.299Z" }, - { url = "https://files.pythonhosted.org/packages/f4/01/54943fc17f4c3ebb256fd5ad5b2b6d19fb0676ee12968da91db6cf2409ff/ruff-0.4.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad1b20e66a44057c326168437d680a2166c177c939346b19c0d6b08a62a37589", size = 10205224, upload-time = "2024-05-31T20:43:45.832Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ad/e8a251c07e67ef4f760e473ec612e42502a83f294fe44aca3aafb4e08f8b/ruff-0.4.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf5d818553add7511c38b05532d94a407f499d1a76ebb0cad0374e32bc67202", size = 8803303, upload-time = "2024-05-31T20:43:49.509Z" }, - { url = "https://files.pythonhosted.org/packages/58/a4/6a2ece523f1d3ccd125b5f1db38a11fcaa252cc452d4c582e4cc27293ec6/ruff-0.4.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50e9651578b629baec3d1513b2534de0ac7ed7753e1382272b8d609997e27e83", size = 8116589, upload-time = "2024-05-31T20:43:52.933Z" }, - { url = "https://files.pythonhosted.org/packages/0f/77/3ad58c9fb2ea6390e2d29c3595119d86ac6fda8187f16e1e5b5066220c2e/ruff-0.4.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8874a9df7766cb956b218a0a239e0a5d23d9e843e4da1e113ae1d27ee420877a", size = 7589687, upload-time = "2024-05-31T20:43:56.301Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d3/f9b2eb5f633790508e203f4d6574c23e3161d0fff4ca0bfe9da19e3e6e8c/ruff-0.4.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b9de9a6e49f7d529decd09381c0860c3f82fa0b0ea00ea78409b785d2308a567", size = 8379595, upload-time = "2024-05-31T20:43:59.182Z" }, - { url = "https://files.pythonhosted.org/packages/55/db/d8d9a8f582ae0ea81181131ff8d092a5fb3e7e4b4781f4ddd51f0793bf4f/ruff-0.4.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:13a1768b0691619822ae6d446132dbdfd568b700ecd3652b20d4e8bc1e498f78", size = 8858060, upload-time = "2024-05-31T20:44:02.33Z" }, - { url = "https://files.pythonhosted.org/packages/2f/57/9e7a6bc709063936d0c2b7ce20ee38c16adaab38034b1a5e80b71ec3f950/ruff-0.4.7-py3-none-win32.whl", hash = "sha256:769e5a51df61e07e887b81e6f039e7ed3573316ab7dd9f635c5afaa310e4030e", size = 7826212, upload-time = "2024-05-31T20:44:06.819Z" }, - { url = "https://files.pythonhosted.org/packages/3b/86/278330ead9f978549130e582457d2a6edfaf0577d463bd589ed8cf9f084e/ruff-0.4.7-py3-none-win_amd64.whl", hash = "sha256:9e3ab684ad403a9ed1226894c32c3ab9c2e0718440f6f50c7c5829932bc9e054", size = 8609712, upload-time = "2024-05-31T20:44:09.567Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e4/174f07c5622df74cc8917b7c3c5eac92ca063e7728e95048010b7314e9df/ruff-0.4.7-py3-none-win_arm64.whl", hash = "sha256:10f2204b9a613988e3484194c2c9e96a22079206b22b787605c255f130db5ed7", size = 7993707, upload-time = "2024-05-31T20:44:13.636Z" }, +version = "0.11.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/f6/adcf73711f31c9f5393862b4281c875a462d9f639f4ccdf69dc368311c20/ruff-0.11.8.tar.gz", hash = "sha256:6d742d10626f9004b781f4558154bb226620a7242080e11caeffab1a40e99df8", size = 4086399, upload-time = "2025-05-01T14:53:24.459Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/60/c6aa9062fa518a9f86cb0b85248245cddcd892a125ca00441df77d79ef88/ruff-0.11.8-py3-none-linux_armv6l.whl", hash = "sha256:896a37516c594805e34020c4a7546c8f8a234b679a7716a3f08197f38913e1a3", size = 10272473, upload-time = "2025-05-01T14:52:37.252Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/0325e50d106dc87c00695f7bcd5044c6d252ed5120ebf423773e00270f50/ruff-0.11.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab86d22d3d721a40dd3ecbb5e86ab03b2e053bc93c700dc68d1c3346b36ce835", size = 11040862, upload-time = "2025-05-01T14:52:41.022Z" }, + { url = "https://files.pythonhosted.org/packages/e6/27/b87ea1a7be37fef0adbc7fd987abbf90b6607d96aa3fc67e2c5b858e1e53/ruff-0.11.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:258f3585057508d317610e8a412788cf726efeefa2fec4dba4001d9e6f90d46c", size = 10385273, upload-time = "2025-05-01T14:52:43.551Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f7/3346161570d789045ed47a86110183f6ac3af0e94e7fd682772d89f7f1a1/ruff-0.11.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:727d01702f7c30baed3fc3a34901a640001a2828c793525043c29f7614994a8c", size = 10578330, upload-time = "2025-05-01T14:52:45.48Z" }, + { url = "https://files.pythonhosted.org/packages/c6/c3/327fb950b4763c7b3784f91d3038ef10c13b2d42322d4ade5ce13a2f9edb/ruff-0.11.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3dca977cc4fc8f66e89900fa415ffe4dbc2e969da9d7a54bfca81a128c5ac219", size = 10122223, upload-time = "2025-05-01T14:52:47.675Z" }, + { url = "https://files.pythonhosted.org/packages/de/c7/ba686bce9adfeb6c61cb1bbadc17d58110fe1d602f199d79d4c880170f19/ruff-0.11.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c657fa987d60b104d2be8b052d66da0a2a88f9bd1d66b2254333e84ea2720c7f", size = 11697353, upload-time = "2025-05-01T14:52:50.264Z" }, + { url = "https://files.pythonhosted.org/packages/53/8e/a4fb4a1ddde3c59e73996bb3ac51844ff93384d533629434b1def7a336b0/ruff-0.11.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f2e74b021d0de5eceb8bd32919f6ff8a9b40ee62ed97becd44993ae5b9949474", size = 12375936, upload-time = "2025-05-01T14:52:52.394Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a1/9529cb1e2936e2479a51aeb011307e7229225df9ac64ae064d91ead54571/ruff-0.11.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9b5ef39820abc0f2c62111f7045009e46b275f5b99d5e59dda113c39b7f4f38", size = 11850083, upload-time = "2025-05-01T14:52:55.424Z" }, + { url = "https://files.pythonhosted.org/packages/3e/94/8f7eac4c612673ae15a4ad2bc0ee62e03c68a2d4f458daae3de0e47c67ba/ruff-0.11.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1dba3135ca503727aa4648152c0fa67c3b1385d3dc81c75cd8a229c4b2a1458", size = 14005834, upload-time = "2025-05-01T14:52:58.056Z" }, + { url = "https://files.pythonhosted.org/packages/1e/7c/6f63b46b2be870cbf3f54c9c4154d13fac4b8827f22fa05ac835c10835b2/ruff-0.11.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f024d32e62faad0f76b2d6afd141b8c171515e4fb91ce9fd6464335c81244e5", size = 11503713, upload-time = "2025-05-01T14:53:01.244Z" }, + { url = "https://files.pythonhosted.org/packages/3a/91/57de411b544b5fe072779678986a021d87c3ee5b89551f2ca41200c5d643/ruff-0.11.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d365618d3ad747432e1ae50d61775b78c055fee5936d77fb4d92c6f559741948", size = 10457182, upload-time = "2025-05-01T14:53:03.726Z" }, + { url = "https://files.pythonhosted.org/packages/01/49/cfe73e0ce5ecdd3e6f1137bf1f1be03dcc819d1bfe5cff33deb40c5926db/ruff-0.11.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4d9aaa91035bdf612c8ee7266153bcf16005c7c7e2f5878406911c92a31633cb", size = 10101027, upload-time = "2025-05-01T14:53:06.555Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/a5cfe47c62b3531675795f38a0ef1c52ff8de62eaddf370d46634391a3fb/ruff-0.11.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0eba551324733efc76116d9f3a0d52946bc2751f0cd30661564117d6fd60897c", size = 11111298, upload-time = "2025-05-01T14:53:08.825Z" }, + { url = "https://files.pythonhosted.org/packages/36/98/f76225f87e88f7cb669ae92c062b11c0a1e91f32705f829bd426f8e48b7b/ruff-0.11.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:161eb4cff5cfefdb6c9b8b3671d09f7def2f960cee33481dd898caf2bcd02304", size = 11566884, upload-time = "2025-05-01T14:53:11.626Z" }, + { url = "https://files.pythonhosted.org/packages/de/7e/fff70b02e57852fda17bd43f99dda37b9bcf3e1af3d97c5834ff48d04715/ruff-0.11.8-py3-none-win32.whl", hash = "sha256:5b18caa297a786465cc511d7f8be19226acf9c0a1127e06e736cd4e1878c3ea2", size = 10451102, upload-time = "2025-05-01T14:53:14.303Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a9/eaa571eb70648c9bde3120a1d5892597de57766e376b831b06e7c1e43945/ruff-0.11.8-py3-none-win_amd64.whl", hash = "sha256:6e70d11043bef637c5617297bdedec9632af15d53ac1e1ba29c448da9341b0c4", size = 11597410, upload-time = "2025-05-01T14:53:16.571Z" }, + { url = "https://files.pythonhosted.org/packages/cd/be/f6b790d6ae98f1f32c645f8540d5c96248b72343b0a56fab3a07f2941897/ruff-0.11.8-py3-none-win_arm64.whl", hash = "sha256:304432e4c4a792e3da85b7699feb3426a0908ab98bf29df22a31b0cdd098fac2", size = 10713129, upload-time = "2025-05-01T14:53:22.27Z" }, ] [[package]] From 25c3810b94b45d5681f4a4886f3d4a6f6db42d8b Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:43:22 -0400 Subject: [PATCH 13/24] DEV: update links in docs --- docs/FragmentRetro/fragmenter-base.md | 2 +- docs/FragmentRetro/fragmenter.md | 2 +- docs/FragmentRetro/retrosynthesis.md | 2 +- docs/FragmentRetro/solutions.md | 2 +- docs/FragmentRetro/substructure-matcher.md | 2 +- docs/FragmentRetro/{utils/type-definition.md => typing.md} | 6 +++--- docs/FragmentRetro/utils/filter-compound.md | 2 +- docs/FragmentRetro/utils/helper.md | 2 +- docs/app/interface.md | 4 ++-- src/fragmentretro/fragmenter_base.py | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) rename docs/FragmentRetro/{utils/type-definition.md => typing.md} (68%) diff --git a/docs/FragmentRetro/fragmenter-base.md b/docs/FragmentRetro/fragmenter-base.md index 12386ea..6b9329e 100644 --- a/docs/FragmentRetro/fragmenter-base.md +++ b/docs/FragmentRetro/fragmenter-base.md @@ -28,7 +28,7 @@ class TestFragmenter(Fragmenter): ## Source Code -::: FragmentRetro.fragmenter_base +::: fragmentretro.fragmenter_base handler: python options: show_root_heading: true diff --git a/docs/FragmentRetro/fragmenter.md b/docs/FragmentRetro/fragmenter.md index f4a7a70..9b1ff41 100644 --- a/docs/FragmentRetro/fragmenter.md +++ b/docs/FragmentRetro/fragmenter.md @@ -16,7 +16,7 @@ fragmenter.visualize(figsize=(20, 10), verbose=False, with_indices=True) ## Source Code -::: FragmentRetro.fragmenter +::: fragmentretro.fragmenter handler: python options: show_root_heading: true diff --git a/docs/FragmentRetro/retrosynthesis.md b/docs/FragmentRetro/retrosynthesis.md index 5a8a3aa..2c50009 100644 --- a/docs/FragmentRetro/retrosynthesis.md +++ b/docs/FragmentRetro/retrosynthesis.md @@ -44,7 +44,7 @@ retro_solution.visualize_solutions(retro_solution.solutions, molsPerRow=4)[-1] ## Source Code -::: FragmentRetro.retrosynthesis +::: fragmentretro.retrosynthesis handler: python options: show_root_heading: true diff --git a/docs/FragmentRetro/solutions.md b/docs/FragmentRetro/solutions.md index bcc16d8..a1fa055 100644 --- a/docs/FragmentRetro/solutions.md +++ b/docs/FragmentRetro/solutions.md @@ -32,7 +32,7 @@ for i, img in enumerate(images): ## Source Code -::: FragmentRetro.solutions +::: fragmentretro.solutions handler: python options: show_root_heading: true diff --git a/docs/FragmentRetro/substructure-matcher.md b/docs/FragmentRetro/substructure-matcher.md index 9452db7..74e2119 100644 --- a/docs/FragmentRetro/substructure-matcher.md +++ b/docs/FragmentRetro/substructure-matcher.md @@ -16,7 +16,7 @@ print(SubstructureMatcher.is_strict_substructure(fragment_smiles, molecule_smile ## Source Code -::: FragmentRetro.substructure_matcher +::: fragmentretro.substructure_matcher handler: python options: show_root_heading: true diff --git a/docs/FragmentRetro/utils/type-definition.md b/docs/FragmentRetro/typing.md similarity index 68% rename from docs/FragmentRetro/utils/type-definition.md rename to docs/FragmentRetro/typing.md index 3b4882b..b542fa2 100644 --- a/docs/FragmentRetro/utils/type-definition.md +++ b/docs/FragmentRetro/typing.md @@ -1,6 +1,6 @@ # Type Definitions -[type_definitions.py](/src/FragmentRetro/type_definitions.py) is a good place to store your type definitions to make code clean and pass mypy tests. +[typing.py](/src/fragmentretro/typing.py) is a good place to store your type definitions to make code clean and pass mypy tests. ## Example Usage @@ -9,7 +9,7 @@ def _find_fragmentation_bonds(mol: Mol) -> list[BondType]: return list(FindBRICSBonds(mol)) ``` -where `BondType` is defined in [type_definitions.py](/src/FragmentRetro/utils/type_definitions.py) as: +where `BondType` is defined in [typing.py](/src/fragmentretro/typing.py) as: ```python BondType: TypeAlias = tuple[tuple[int, int], tuple[str, str]] @@ -17,7 +17,7 @@ BondType: TypeAlias = tuple[tuple[int, int], tuple[str, str]] ## Source Code -::: FragmentRetro.utils.type_definitions +::: fragmentretro.typing handler: python options: show_root_heading: true diff --git a/docs/FragmentRetro/utils/filter-compound.md b/docs/FragmentRetro/utils/filter-compound.md index ebf56cc..8e277cb 100644 --- a/docs/FragmentRetro/utils/filter-compound.md +++ b/docs/FragmentRetro/utils/filter-compound.md @@ -39,7 +39,7 @@ filtered_indices, filtered_BBs = compound_filter.get_filtered_BBs(fragment_smile ## Source Code -::: FragmentRetro.utils.filter_compound +::: fragmentretro.utils.filter_compound handler: python options: show_root_heading: true diff --git a/docs/FragmentRetro/utils/helper.md b/docs/FragmentRetro/utils/helper.md index 6c0a7cf..6a2f989 100644 --- a/docs/FragmentRetro/utils/helper.md +++ b/docs/FragmentRetro/utils/helper.md @@ -40,7 +40,7 @@ print(f"SMILES without indices: {smiles_without_indices}") ## Source Code -::: FragmentRetro.utils.helpers +::: fragmentretro.utils.helpers handler: python options: show_root_heading: true diff --git a/docs/app/interface.md b/docs/app/interface.md index 1e0f9cc..c0f0588 100644 --- a/docs/app/interface.md +++ b/docs/app/interface.md @@ -26,7 +26,7 @@ app = display_gui(smiles="CCNCC") ## Source Code -::: app.interface +::: fragmentretro.app.interface handler: python options: show_root_heading: true @@ -34,7 +34,7 @@ app = display_gui(smiles="CCNCC") members: - display_gui -::: app.gui.controller +::: fragmentretro.app.gui.controller handler: python options: show_root_heading: true diff --git a/src/fragmentretro/fragmenter_base.py b/src/fragmentretro/fragmenter_base.py index bec1a50..6d838d3 100644 --- a/src/fragmentretro/fragmenter_base.py +++ b/src/fragmentretro/fragmenter_base.py @@ -215,7 +215,7 @@ def check_connected_subgraph(self, combination: CombType) -> bool: """ # check if the combination is a connected subgraph subgraph = self.fragment_graph.subgraph(combination) - return nx.is_connected(subgraph) + return cast(bool, nx.is_connected(subgraph)) def get_combination_smiles(self, combination: CombType) -> str: """ From 77c826a8149a875ac60c4fd22ca54c2665d0adc5 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 17:44:02 -0400 Subject: [PATCH 14/24] DEV: ensure formatting --- src/fragmentretro/app/gui/controller.py | 2 +- src/fragmentretro/retrosynthesis.py | 4 ++-- src/fragmentretro/substructure_matcher.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fragmentretro/app/gui/controller.py b/src/fragmentretro/app/gui/controller.py index 3fd1356..120dc3d 100644 --- a/src/fragmentretro/app/gui/controller.py +++ b/src/fragmentretro/app/gui/controller.py @@ -365,7 +365,7 @@ def display_solutions_on_click(self, b: widgets.Button) -> None: logger.info(f"[GUI] Generated {num_valid_images} image(s). Use dropdown to view.") dropdown_options: list[tuple[str, int]] = [ - (f"Solution {original_indices[i]+1}", i) for i in range(num_valid_images) if original_indices[i] != -1 + (f"Solution {original_indices[i] + 1}", i) for i in range(num_valid_images) if original_indices[i] != -1 ] self.solution_dropdown.options = dropdown_options self.solution_dropdown.value = 0 if dropdown_options else None diff --git a/src/fragmentretro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py index ce1e2a9..25b72ea 100644 --- a/src/fragmentretro/retrosynthesis.py +++ b/src/fragmentretro/retrosynthesis.py @@ -41,9 +41,9 @@ def __init__( self.last_stage_combs: list[CombType] if original_BBs is not None and mol_properties_path is not None: - logger.warn("Both original_BBs and mol_properties_path are provided. " "Will be using mol_properties_path.") + logger.warn("Both original_BBs and mol_properties_path are provided. Will be using mol_properties_path.") elif mol_properties_path is not None and compound_filter is not None: - logger.warn("Both mol_properties_path and compound_filter are provided. " "Will be using compound_filter.") + logger.warn("Both mol_properties_path and compound_filter are provided. Will be using compound_filter.") elif original_BBs is None and mol_properties_path is None and compound_filter is None: logger.critical("Either original_BBs, mol_properties_path, or compound_filter must be provided.") if mol_properties_path is not None: diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index 4662087..3552bfd 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -124,7 +124,7 @@ def addH_to_wildcard_neighbors(fragment_smarts: str) -> str: # remove chirality information (in re group \1) for atoms with dummy neighbors smarts_with_indices = re.sub( rf"\[\#{atomic_num}(@*)&H{num_hydrogens}:{idx}\]", - rf"[#{atomic_num}&H{num_hydrogens},#{atomic_num}&H{num_hydrogens+1}:{idx}]", + rf"[#{atomic_num}&H{num_hydrogens},#{atomic_num}&H{num_hydrogens + 1}:{idx}]", smarts_with_indices, ) logger.debug("smarts_with_indices: %s", smarts_with_indices) From 7bdfd18e150a731fe703aeb92b7ae8f2906ef7d2 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 18:01:51 -0400 Subject: [PATCH 15/24] MAINT: refresh mkdocs versions --- docs/FragmentRetro/typing.md | 8 ++-- docs/dev/introduction.md | 23 ++++++------ pyproject.toml | 6 +-- uv.lock | 71 ++++++++++++------------------------ 4 files changed, 43 insertions(+), 65 deletions(-) diff --git a/docs/FragmentRetro/typing.md b/docs/FragmentRetro/typing.md index b542fa2..c4959c9 100644 --- a/docs/FragmentRetro/typing.md +++ b/docs/FragmentRetro/typing.md @@ -1,18 +1,20 @@ # Type Definitions -[typing.py](/src/fragmentretro/typing.py) is a good place to store your type definitions to make code clean and pass mypy tests. +`fragmentretro.typing` is a good place to store your type definitions to make code clean and pass mypy tests. ## Example Usage ```python +from fragmentretro.typing import BondType + def _find_fragmentation_bonds(mol: Mol) -> list[BondType]: return list(FindBRICSBonds(mol)) ``` -where `BondType` is defined in [typing.py](/src/fragmentretro/typing.py) as: +where `BondType` is defined in `fragmentretro.typing` as: ```python -BondType: TypeAlias = tuple[tuple[int, int], tuple[str, str]] +type BondType = tuple[tuple[int, int], tuple[str, str]] ``` ## Source Code diff --git a/docs/dev/introduction.md b/docs/dev/introduction.md index 101356e..7a42255 100644 --- a/docs/dev/introduction.md +++ b/docs/dev/introduction.md @@ -2,12 +2,18 @@ ## Development -If you need other packages to run your features, you must specify the dependency in [pyproject.toml](./pyproject.toml) and the version used. +If you need other packages to run your features, you must specify the dependency in `pyproject.toml` and the version used. If you run + +```bash +uv add package +``` + +pyproject.toml will be updated automatically. ### Set Up ```bash -uv venv --python 3.11.4 +uv venv ``` which will create a new virtual environment (in the folder `venv` which is already gitignored). @@ -18,7 +24,7 @@ Activate the environment: source .venv/bin/activate ``` -and install all dependencies (specified in [pyproject.toml](./pyproject.toml)): +and install all dependencies (specified in `pyproject.toml`): ```bash uv pip install -e ".[dev]" @@ -33,19 +39,14 @@ uv pip install -e ".[dev]" #### Pre-Commits -After `pre-commit install`, each time you try to make a commit, the system will automatically check for: - -- linting errors (using [ruff](https://github.com/astral-sh/ruff)) -- formatting (using [black](https://github.com/psf/black)) -- import sorting (using [isort](https://github.com/pycqa/isort/)) - this is arguably the least necessary thing, but once you have it as a pre-commit hook, you forget it even exists. +After `pre-commit install`, each time you try to make a commit, the system will automatically check for formatting and linting errors (using [ruff](https://github.com/astral-sh/ruff)) > mypy from pre-commit hooks currently disabled just so that you can push commits even with failing mypy so that we can discuss it on GitHub and see how it can be fixed -If any of the checks above (ruff/black/isort) fail, the system will try to fix them automatically, so in most cases you'll only need to run `git add .` and try to commit again. If you want run the checks manually, you can do: +If any of the checks above (ruff) fail, the system will try to fix them automatically, so in most cases you'll only need to run `git add .` and try to commit again. If you want run the checks manually, you can do: - `ruff check`. If there are errors, most of the time they can be fixed by `ruff check --fix`. Some errors will need to be fixed manually though. -- `black .` (notice the dot). This simply applies black formatting to the whole repo. -- `isort --profile black .` (notice the dot). This applies import sorting. You almost never need to run black/isort manually, pre-commit will take care of that. +- `ruff format` to format the code according to the [Black](https://black.readthedocs.io/en/stable/) style guide. #### MyPy diff --git a/pyproject.toml b/pyproject.toml index 1dc5e11..fc213ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,14 +32,14 @@ package-dir = { "" = "src" } [project.optional-dependencies] dev = [ - "mkdocs==1.6.1", - "mkdocstrings-python==1.12.2", - "mkdocs-material==9.5.49", "mypy-extensions==1.0.0", "ruff>=0.11.8", "mypy>=1.15.0", "pre-commit>=4.2.0", "pytest>=8.3.5", + "mkdocs>=1.6.1", + "mkdocstrings-python>=1.16.10", + "mkdocs-material>=9.6.12", ] [tool.mypy] diff --git a/uv.lock b/uv.lock index b4822ba..c533737 100644 --- a/uv.lock +++ b/uv.lock @@ -29,6 +29,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] +[[package]] +name = "backrefs" +version = "5.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/46/caba1eb32fa5784428ab401a5487f73db4104590ecd939ed9daaf18b47e0/backrefs-5.8.tar.gz", hash = "sha256:2cab642a205ce966af3dd4b38ee36009b31fa9502a35fd61d59ccc116e40a6bd", size = 6773994, upload-time = "2025-02-25T18:15:32.003Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/cb/d019ab87fe70e0fe3946196d50d6a4428623dc0c38a6669c8cae0320fbf3/backrefs-5.8-py310-none-any.whl", hash = "sha256:c67f6638a34a5b8730812f5101376f9d41dc38c43f1fdc35cb54700f6ed4465d", size = 380337, upload-time = "2025-02-25T16:53:14.607Z" }, + { url = "https://files.pythonhosted.org/packages/a9/86/abd17f50ee21b2248075cb6924c6e7f9d23b4925ca64ec660e869c2633f1/backrefs-5.8-py311-none-any.whl", hash = "sha256:2e1c15e4af0e12e45c8701bd5da0902d326b2e200cafcd25e49d9f06d44bb61b", size = 392142, upload-time = "2025-02-25T16:53:17.266Z" }, + { url = "https://files.pythonhosted.org/packages/b3/04/7b415bd75c8ab3268cc138c76fa648c19495fcc7d155508a0e62f3f82308/backrefs-5.8-py312-none-any.whl", hash = "sha256:bbef7169a33811080d67cdf1538c8289f76f0942ff971222a16034da88a73486", size = 398021, upload-time = "2025-02-25T16:53:26.378Z" }, + { url = "https://files.pythonhosted.org/packages/04/b8/60dcfb90eb03a06e883a92abbc2ab95c71f0d8c9dd0af76ab1d5ce0b1402/backrefs-5.8-py313-none-any.whl", hash = "sha256:e3a63b073867dbefd0536425f43db618578528e3896fb77be7141328642a1585", size = 399915, upload-time = "2025-02-25T16:53:28.167Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/fb6973edeb700f6e3d6ff222400602ab1830446c25c7b4676d8de93e65b8/backrefs-5.8-py39-none-any.whl", hash = "sha256:a66851e4533fb5b371aa0628e1fee1af05135616b86140c9d787a2ffdf4b8fdc", size = 380336, upload-time = "2025-02-25T16:53:29.858Z" }, +] + [[package]] name = "certifi" version = "2025.4.26" @@ -309,9 +322,9 @@ requires-dist = [ { name = "ipykernel", specifier = ">=6.29.5" }, { name = "ipywidgets", specifier = "==8.1.6" }, { name = "matplotlib", specifier = "==3.10.0" }, - { name = "mkdocs", marker = "extra == 'dev'", specifier = "==1.6.1" }, - { name = "mkdocs-material", marker = "extra == 'dev'", specifier = "==9.5.49" }, - { name = "mkdocstrings-python", marker = "extra == 'dev'", specifier = "==1.12.2" }, + { name = "mkdocs", marker = "extra == 'dev'", specifier = ">=1.6.1" }, + { name = "mkdocs-material", marker = "extra == 'dev'", specifier = ">=9.6.12" }, + { name = "mkdocstrings-python", marker = "extra == 'dev'", specifier = ">=1.16.10" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.15.0" }, { name = "mypy-extensions", marker = "extra == 'dev'", specifier = "==1.0.0" }, { name = "networkx", specifier = "==3.4.2" }, @@ -723,10 +736,11 @@ wheels = [ [[package]] name = "mkdocs-material" -version = "9.5.49" +version = "9.6.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "babel" }, + { name = "backrefs" }, { name = "colorama" }, { name = "jinja2" }, { name = "markdown" }, @@ -735,12 +749,11 @@ dependencies = [ { name = "paginate" }, { name = "pygments" }, { name = "pymdown-extensions" }, - { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e2/14/8daeeecee2e25bd84239a843fdcb92b20db88ebbcb26e0d32f414ca54a22/mkdocs_material-9.5.49.tar.gz", hash = "sha256:3671bb282b4f53a1c72e08adbe04d2481a98f85fed392530051f80ff94a9621d", size = 3949559, upload-time = "2024-12-16T10:25:10.539Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/ef/25fc10dbbb8faeeeb10ed7734d84a347cd2ec5d7200733f11c5553c02608/mkdocs_material-9.6.12.tar.gz", hash = "sha256:add6a6337b29f9ea7912cb1efc661de2c369060b040eb5119855d794ea85b473", size = 3951532, upload-time = "2025-04-17T10:40:41.48Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/2d/2dd23a36b48421db54f118bb6f6f733dbe2d5c78fe7867375e48649fd3df/mkdocs_material-9.5.49-py3-none-any.whl", hash = "sha256:c3c2d8176b18198435d3a3e119011922f3e11424074645c24019c2dcf08a360e", size = 8684098, upload-time = "2024-12-16T10:25:02.326Z" }, + { url = "https://files.pythonhosted.org/packages/09/00/592940f4d150327a4f455171b2c9d4c3be7779a88e18b0a086183fcd8f06/mkdocs_material-9.6.12-py3-none-any.whl", hash = "sha256:92b4fbdc329e4febc267ca6e2c51e8501fa97b2225c5f4deb4d4e43550f8e61e", size = 8703654, upload-time = "2025-04-17T10:40:38.304Z" }, ] [[package]] @@ -771,16 +784,16 @@ wheels = [ [[package]] name = "mkdocstrings-python" -version = "1.12.2" +version = "1.16.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "griffe" }, { name = "mkdocs-autorefs" }, { name = "mkdocstrings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/23/ec/cb6debe2db77f1ef42b25b21d93b5021474de3037cd82385e586aee72545/mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3", size = 168207, upload-time = "2024-10-19T17:54:41.672Z" } +sdist = { url = "https://files.pythonhosted.org/packages/44/c8/600c4201b6b9e72bab16802316d0c90ce04089f8e6bb5e064cd2a5abba7e/mkdocstrings_python-1.16.10.tar.gz", hash = "sha256:f9eedfd98effb612ab4d0ed6dd2b73aff6eba5215e0a65cea6d877717f75502e", size = 205771, upload-time = "2025-04-03T14:24:48.12Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/c1/ac524e1026d9580cbc654b5d19f5843c8b364a66d30f956372cd09fd2f92/mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a", size = 111759, upload-time = "2024-10-19T17:54:39.338Z" }, + { url = "https://files.pythonhosted.org/packages/53/37/19549c5e0179785308cc988a68e16aa7550e4e270ec8a9878334e86070c6/mkdocstrings_python-1.16.10-py3-none-any.whl", hash = "sha256:63bb9f01f8848a644bdb6289e86dc38ceddeaa63ecc2e291e3b2ca52702a6643", size = 124112, upload-time = "2025-04-03T14:24:46.561Z" }, ] [[package]] @@ -1203,44 +1216,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/63/a164a042b6c6f6e753d1250f4f7d9762c4d8ffa41e97d31c1272454f51f4/rdkit-2023.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:ac410c68415d4f1f6587e7edba49e272a798c871fc9d98cc323fc196f1c2c41f", size = 21012337, upload-time = "2023-12-22T15:47:23.928Z" }, ] -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - [[package]] name = "requests" version = "2.32.3" From fe306778c2765aa19bcb2916192549707d6b5bb5 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 18:12:12 -0400 Subject: [PATCH 16/24] GIT: add a few nice things to mkdocs --- docs/CNAME | 1 + docs/stylesheets/extra.css | 24 +++++++++++++++++++++++ mkdocs.yml | 40 ++++++++++++++++++++++++++++++++++---- 3 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 docs/CNAME create mode 100644 docs/stylesheets/extra.css diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..6be68eb --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +fragment.batistalab.com \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 0000000..ffdf97d --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,24 @@ +html { + font-size: 18px; + } + + + h1 { + font-weight: 600 !important; + color: #333 !important; + } + + [data-md-color-scheme="slate"] h1 { + font-weight: 600 !important; + color: #d7d7d7 !important; + } + + h2 { + font-weight: 600 !important; + color: #333 !important; + } + + [data-md-color-scheme="slate"] h2 { + font-weight: 600 !important; + color: #d7d7d7 !important; + } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 46ef8fb..8508265 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,16 +1,45 @@ +repo_url: https://github.com/randyshee/FragmentRetro +repo_name: randyshee/FragmentRetro +copyright: MIT © 2025 Randy Shee site_name: FragmentRetro Docs theme: name: material features: - content.code.copy + - navigation.footer + palette: + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to light mode + +extra_css: +- stylesheets/extra.css + +extra: + version: + provider: mike + plugins: - search - mkdocstrings: handlers: - python: - paths: - - src + python: + options: + show_source: true + show_submodules: true + docstring_style: google + show_signature: true + members_order: source markdown_extensions: - pymdownx.highlight: @@ -22,4 +51,7 @@ markdown_extensions: - pymdownx.superfences - def_list - pymdownx.tasklist: - custom_checkbox: true \ No newline at end of file + custom_checkbox: true + + - admonition + - pymdownx.details \ No newline at end of file From d6966698dbc652bc69c27eba16e2545d434d14db Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 18:35:52 -0400 Subject: [PATCH 17/24] GIT: return tests, fix an issue in r_brics, stop ignoring r_brics for mypy --- .github/workflows/quality.yml | 4 +- .github/workflows/tests.yml | 43 ++++++++++++++++++++++ pyproject.toml | 2 +- src/fragmentretro/fragmentation/r_brics.py | 6 ++- 4 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 59117a2..b4c3f63 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -3,7 +3,7 @@ name: Code Quality on: [push, pull_request] jobs: - lint: + qualitycheck: runs-on: ubuntu-latest steps: @@ -46,4 +46,4 @@ jobs: run: ruff format --check - name: Run mypy - run: mypy . \ No newline at end of file + run: mypy . diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..696bed5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,43 @@ +name: Tests + +on: [push, pull_request] +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v4 + with: + python-version: '3.12' + + - name: Install uv + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cache/uv + ~/.uv + .venv + key: ${{ runner.os }}-uv-${{ hashFiles('pyproject.toml') }} + restore-keys: | + ${{ runner.os }}-uv- + + - name: Create and activate virtual environment + run: | + uv venv + echo "$PWD/.venv/bin" >> $GITHUB_PATH + + - name: Install dependencies + run: uv pip install -e ".[dev]" + + - name: Run tests with coverage + run: | + pytest -v --cov=fragmentretro --cov-report=xml --cov-report=term diff --git a/pyproject.toml b/pyproject.toml index fc213ce..125654b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ dev = [ [tool.mypy] strict = true ignore_missing_imports = true -exclude = ["tests", "src/fragmentation/r_brics.py"] +exclude = ["tests"] disable_error_code = ["unused-ignore"] [[tool.mypy.overrides]] diff --git a/src/fragmentretro/fragmentation/r_brics.py b/src/fragmentretro/fragmentation/r_brics.py index e553f62..b7ee1a0 100644 --- a/src/fragmentretro/fragmentation/r_brics.py +++ b/src/fragmentretro/fragmentation/r_brics.py @@ -379,10 +379,11 @@ def initialize_bond_matchers( def init_reactions( environments: EnvironmentSmartsMap, reaction_definitions: BondCleavageDefinitions -) -> tuple[list[SmartsPattern], ReactionGroups, ReactionList]: +) -> tuple[list[list[SmartsPattern]], ReactionGroups, ReactionList]: rule_groups = copy.deepcopy(reaction_definitions) smarts_groups = [] for rule_group in rule_groups: + new_rule_group = [] for rule in rule_group: env_idx1, env_idx2, bond = rule smarts1 = environs["L" + env_idx1] @@ -396,9 +397,10 @@ def init_reactions( else: # sma = "[$(%s):1]%s[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]" % (smarts1, bond, smarts2, g1, g2) sma = f"[$({smarts1})]{bond}[$({smarts2})]>>[{g1}*]-[*:1].[{g2}*]-[*:2]" - smarts_groups.append(sma) + new_rule_group.append(sma) # sma='[$(%s):1]%s;!@[$(%s):2]>>[%s*]-[*:1].[%s*]-[*:2]'%(r1,bnd,r2,g1,g2) #original # gp[j] =sma + smarts_groups.append(new_rule_group) for smarts_group in smarts_groups: for smarts in smarts_group: From bfd2be82d46b7a24c70b0b1278e1f1a4fc8fd7bc Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 18:38:04 -0400 Subject: [PATCH 18/24] MAINT: add pytest-cov --- pyproject.toml | 1 + uv.lock | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 125654b..06b407a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ dev = [ "mkdocs>=1.6.1", "mkdocstrings-python>=1.16.10", "mkdocs-material>=9.6.12", + "pytest-cov>=6.1.1", ] [tool.mypy] diff --git a/uv.lock b/uv.lock index c533737..8b795d3 100644 --- a/uv.lock +++ b/uv.lock @@ -202,6 +202,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, ] +[[package]] +name = "coverage" +version = "7.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/4f/2251e65033ed2ce1e68f00f91a0294e0f80c80ae8c3ebbe2f12828c4cd53/coverage-7.8.0.tar.gz", hash = "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501", size = 811872, upload-time = "2025-03-30T20:36:45.376Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/12/4792669473297f7973518bec373a955e267deb4339286f882439b8535b39/coverage-7.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc", size = 211684, upload-time = "2025-03-30T20:35:29.959Z" }, + { url = "https://files.pythonhosted.org/packages/be/e1/2a4ec273894000ebedd789e8f2fc3813fcaf486074f87fd1c5b2cb1c0a2b/coverage-7.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6", size = 211935, upload-time = "2025-03-30T20:35:31.912Z" }, + { url = "https://files.pythonhosted.org/packages/f8/3a/7b14f6e4372786709a361729164125f6b7caf4024ce02e596c4a69bccb89/coverage-7.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d", size = 245994, upload-time = "2025-03-30T20:35:33.455Z" }, + { url = "https://files.pythonhosted.org/packages/54/80/039cc7f1f81dcbd01ea796d36d3797e60c106077e31fd1f526b85337d6a1/coverage-7.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05", size = 242885, upload-time = "2025-03-30T20:35:35.354Z" }, + { url = "https://files.pythonhosted.org/packages/10/e0/dc8355f992b6cc2f9dcd5ef6242b62a3f73264893bc09fbb08bfcab18eb4/coverage-7.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a", size = 245142, upload-time = "2025-03-30T20:35:37.121Z" }, + { url = "https://files.pythonhosted.org/packages/43/1b/33e313b22cf50f652becb94c6e7dae25d8f02e52e44db37a82de9ac357e8/coverage-7.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6", size = 244906, upload-time = "2025-03-30T20:35:39.07Z" }, + { url = "https://files.pythonhosted.org/packages/05/08/c0a8048e942e7f918764ccc99503e2bccffba1c42568693ce6955860365e/coverage-7.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47", size = 243124, upload-time = "2025-03-30T20:35:40.598Z" }, + { url = "https://files.pythonhosted.org/packages/5b/62/ea625b30623083c2aad645c9a6288ad9fc83d570f9adb913a2abdba562dd/coverage-7.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe", size = 244317, upload-time = "2025-03-30T20:35:42.204Z" }, + { url = "https://files.pythonhosted.org/packages/62/cb/3871f13ee1130a6c8f020e2f71d9ed269e1e2124aa3374d2180ee451cee9/coverage-7.8.0-cp312-cp312-win32.whl", hash = "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545", size = 214170, upload-time = "2025-03-30T20:35:44.216Z" }, + { url = "https://files.pythonhosted.org/packages/88/26/69fe1193ab0bfa1eb7a7c0149a066123611baba029ebb448500abd8143f9/coverage-7.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b", size = 214969, upload-time = "2025-03-30T20:35:45.797Z" }, + { url = "https://files.pythonhosted.org/packages/f3/21/87e9b97b568e223f3438d93072479c2f36cc9b3f6b9f7094b9d50232acc0/coverage-7.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd", size = 211708, upload-time = "2025-03-30T20:35:47.417Z" }, + { url = "https://files.pythonhosted.org/packages/75/be/882d08b28a0d19c9c4c2e8a1c6ebe1f79c9c839eb46d4fca3bd3b34562b9/coverage-7.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00", size = 211981, upload-time = "2025-03-30T20:35:49.002Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/ce99612ebd58082fbe3f8c66f6d8d5694976c76a0d474503fa70633ec77f/coverage-7.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64", size = 245495, upload-time = "2025-03-30T20:35:51.073Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8d/6115abe97df98db6b2bd76aae395fcc941d039a7acd25f741312ced9a78f/coverage-7.8.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067", size = 242538, upload-time = "2025-03-30T20:35:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/cb/74/2f8cc196643b15bc096d60e073691dadb3dca48418f08bc78dd6e899383e/coverage-7.8.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008", size = 244561, upload-time = "2025-03-30T20:35:54.658Z" }, + { url = "https://files.pythonhosted.org/packages/22/70/c10c77cd77970ac965734fe3419f2c98665f6e982744a9bfb0e749d298f4/coverage-7.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733", size = 244633, upload-time = "2025-03-30T20:35:56.221Z" }, + { url = "https://files.pythonhosted.org/packages/38/5a/4f7569d946a07c952688debee18c2bb9ab24f88027e3d71fd25dbc2f9dca/coverage-7.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323", size = 242712, upload-time = "2025-03-30T20:35:57.801Z" }, + { url = "https://files.pythonhosted.org/packages/bb/a1/03a43b33f50475a632a91ea8c127f7e35e53786dbe6781c25f19fd5a65f8/coverage-7.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3", size = 244000, upload-time = "2025-03-30T20:35:59.378Z" }, + { url = "https://files.pythonhosted.org/packages/6a/89/ab6c43b1788a3128e4d1b7b54214548dcad75a621f9d277b14d16a80d8a1/coverage-7.8.0-cp313-cp313-win32.whl", hash = "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d", size = 214195, upload-time = "2025-03-30T20:36:01.005Z" }, + { url = "https://files.pythonhosted.org/packages/12/12/6bf5f9a8b063d116bac536a7fb594fc35cb04981654cccb4bbfea5dcdfa0/coverage-7.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487", size = 214998, upload-time = "2025-03-30T20:36:03.006Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e6/1e9df74ef7a1c983a9c7443dac8aac37a46f1939ae3499424622e72a6f78/coverage-7.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25", size = 212541, upload-time = "2025-03-30T20:36:04.638Z" }, + { url = "https://files.pythonhosted.org/packages/04/51/c32174edb7ee49744e2e81c4b1414ac9df3dacfcb5b5f273b7f285ad43f6/coverage-7.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42", size = 212767, upload-time = "2025-03-30T20:36:06.503Z" }, + { url = "https://files.pythonhosted.org/packages/e9/8f/f454cbdb5212f13f29d4a7983db69169f1937e869a5142bce983ded52162/coverage-7.8.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502", size = 256997, upload-time = "2025-03-30T20:36:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e6/74/2bf9e78b321216d6ee90a81e5c22f912fc428442c830c4077b4a071db66f/coverage-7.8.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1", size = 252708, upload-time = "2025-03-30T20:36:09.781Z" }, + { url = "https://files.pythonhosted.org/packages/92/4d/50d7eb1e9a6062bee6e2f92e78b0998848a972e9afad349b6cdde6fa9e32/coverage-7.8.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4", size = 255046, upload-time = "2025-03-30T20:36:11.409Z" }, + { url = "https://files.pythonhosted.org/packages/40/9e/71fb4e7402a07c4198ab44fc564d09d7d0ffca46a9fb7b0a7b929e7641bd/coverage-7.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73", size = 256139, upload-time = "2025-03-30T20:36:13.86Z" }, + { url = "https://files.pythonhosted.org/packages/49/1a/78d37f7a42b5beff027e807c2843185961fdae7fe23aad5a4837c93f9d25/coverage-7.8.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a", size = 254307, upload-time = "2025-03-30T20:36:16.074Z" }, + { url = "https://files.pythonhosted.org/packages/58/e9/8fb8e0ff6bef5e170ee19d59ca694f9001b2ec085dc99b4f65c128bb3f9a/coverage-7.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883", size = 255116, upload-time = "2025-03-30T20:36:18.033Z" }, + { url = "https://files.pythonhosted.org/packages/56/b0/d968ecdbe6fe0a863de7169bbe9e8a476868959f3af24981f6a10d2b6924/coverage-7.8.0-cp313-cp313t-win32.whl", hash = "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada", size = 214909, upload-time = "2025-03-30T20:36:19.644Z" }, + { url = "https://files.pythonhosted.org/packages/87/e9/d6b7ef9fecf42dfb418d93544af47c940aa83056c49e6021a564aafbc91f/coverage-7.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257", size = 216068, upload-time = "2025-03-30T20:36:21.282Z" }, + { url = "https://files.pythonhosted.org/packages/59/f1/4da7717f0063a222db253e7121bd6a56f6fb1ba439dcc36659088793347c/coverage-7.8.0-py3-none-any.whl", hash = "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7", size = 203435, upload-time = "2025-03-30T20:36:43.61Z" }, +] + [[package]] name = "cycler" version = "0.12.1" @@ -314,6 +353,7 @@ dev = [ { name = "mypy-extensions" }, { name = "pre-commit" }, { name = "pytest" }, + { name = "pytest-cov" }, { name = "ruff" }, ] @@ -331,6 +371,7 @@ requires-dist = [ { name = "numpy", specifier = "==1.26.4" }, { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=4.2.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.5" }, + { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=6.1.1" }, { name = "rdkit", specifier = "==2023.9.3" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.11.8" }, { name = "tomli", specifier = ">=2.2.1" }, @@ -1096,6 +1137,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, ] +[[package]] +name = "pytest-cov" +version = "6.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/69/5f1e57f6c5a39f81411b550027bf72842c4567ff5fd572bed1edc9e4b5d9/pytest_cov-6.1.1.tar.gz", hash = "sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a", size = 66857, upload-time = "2025-04-05T14:07:51.592Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/d0/def53b4a790cfb21483016430ed828f64830dd981ebe1089971cd10cab25/pytest_cov-6.1.1-py3-none-any.whl", hash = "sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde", size = 23841, upload-time = "2025-04-05T14:07:49.641Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" From efc608896262c91376992234934ff00951186c43 Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 18:40:29 -0400 Subject: [PATCH 19/24] git: ignore app files in coverage --- pyproject.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 06b407a..3e95088 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,3 +68,13 @@ lint.ignore = [ "SIM108", # disagree w/ https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp/ ] exclude = ["tests"] + +[tool.ruff.lint.per-file-ignores] +"tests/**/*.py" = ["E501"] # Ignore line length in tests + +[tool.coverage.run] +omit = [ + # omit basis set files + "*/fragmentretro/app/**/*.py", + "*/__init__.py", +] \ No newline at end of file From 057105d1aa224b5ba8064e0086f637423730d0fe Mon Sep 17 00:00:00 2001 From: Anton Morgunov Date: Sat, 3 May 2025 18:46:58 -0400 Subject: [PATCH 20/24] DOCS: minor changes --- docs/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.md b/docs/index.md index bd677b5..47e29e8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,7 +9,7 @@ FragmentRetro is a fragment-based retrosynthetic method with quadratic complexit You can install the package after cloning the repo: ```bash -uv venv --python 3.11.4 +uv venv source .venv/bin/activate uv pip install -e . ``` @@ -29,7 +29,7 @@ Here's a quick example to obtain retrosynthesis solutions: ```python from pathlib import Path -from fragmentretro.fragmenter import BRICSFragmenter # or rBRICSFragmenter +from fragmentretro.fragmenter import rBRICSFragmenter # or BRICSFragmenter from fragmentretro.retrosynthesis import Retrosynthesis from fragmentretro.solutions import RetrosynthesisSolution @@ -39,7 +39,7 @@ PRECOMPUTE_PATH = DATA_PATH / "precompute" JSON_PRECOMPUTE_PATH = PRECOMPUTE_PATH / "n1_stock_properties.json" target = "COc1ccc(F)c(-c2ccc(COc3cccc(C(CC(=O)O)C4CC4)c3)nc2CC(C)(C)C)c1" -fragmenter = BRICSFragmenter(target) # or rBRICSFragmenter +fragmenter = rBRICSFragmenter(target) # or BRICSFragmenter retro_tool = Retrosynthesis(fragmenter, original_BBs=None, mol_properties_path=JSON_PRECOMPUTE_PATH) retro_tool.fragment_retrosynthesis() retro_solution = RetrosynthesisSolution(retro_tool) @@ -81,7 +81,7 @@ app = display_gui(smiles="CCNCC") We welcome any contributions, feel free to clone the repo and create a PR. We recommend using [uv](https://docs.astral.sh/uv/getting-started/installation/): ```bash -uv venv --python 3.11.4 +uv venv source .venv/bin/activate uv pip install -e ".[dev]" ``` From 75f8631ff4b165b106bd32565a19dbf9310724d2 Mon Sep 17 00:00:00 2001 From: randyshee Date: Sat, 3 May 2025 18:54:53 -0400 Subject: [PATCH 21/24] DOCS: name change --- LICENSE | 2 +- mkdocs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 7b96f22..64d8117 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Batista Lab (Yale University) +Copyright (c) 2025 Yu Shee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/mkdocs.yml b/mkdocs.yml index 8508265..f47b0af 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,6 +1,6 @@ repo_url: https://github.com/randyshee/FragmentRetro repo_name: randyshee/FragmentRetro -copyright: MIT © 2025 Randy Shee +copyright: MIT © 2025 Yu Shee site_name: FragmentRetro Docs theme: name: material From c5c739eb57f92cc2fce5ca621da293605de3bfb1 Mon Sep 17 00:00:00 2001 From: randyshee Date: Sat, 3 May 2025 20:29:20 -0400 Subject: [PATCH 22/24] FIX: app import properly --- docs/app/interface.md | 8 +------- src/fragmentretro/app/gui/controller.py | 16 ++++++++-------- src/fragmentretro/app/gui/layout.py | 3 ++- src/fragmentretro/app/interface.py | 9 +++++---- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/docs/app/interface.md b/docs/app/interface.md index c0f0588..1d89a18 100644 --- a/docs/app/interface.md +++ b/docs/app/interface.md @@ -7,14 +7,8 @@ This is the GUI Implementation for FragmentRetro. In a Jupyter notebook: ```python -from app.interface import display_gui +from fragmentretro.app.interface import display_gui -import logging -from fragmentretro.utils.logging_config import logger as fragment_logger -from app.logging_config import logger as app_logger - -# Adjust the logging levels to control the verbosity of the logs or to suppress them -fragment_logger.setLevel(logging.WARNING) app_logger.setLevel(logging.INFO) # To display the GUI without any initial SMILES input diff --git a/src/fragmentretro/app/gui/controller.py b/src/fragmentretro/app/gui/controller.py index 120dc3d..5c69e2d 100644 --- a/src/fragmentretro/app/gui/controller.py +++ b/src/fragmentretro/app/gui/controller.py @@ -4,8 +4,13 @@ from typing import cast import ipywidgets as widgets -from app.gui.state import AppState -from app.gui.widgets import ( +from IPython.display import display +from PIL.Image import Image as PILImage +from rdkit import Chem +from rdkit.Chem import Draw + +from fragmentretro.app.gui.state import AppState +from fragmentretro.app.gui.widgets import ( core_factor_input, display_button, file_path_input, @@ -27,18 +32,13 @@ sort_smiles_button, target_smiles_input, ) -from app.logging_config import logger -from IPython.display import display -from PIL.Image import Image as PILImage -from rdkit import Chem -from rdkit.Chem import Draw - from fragmentretro.fragmenter import BRICSFragmenter, rBRICSFragmenter from fragmentretro.fragmenter_base import Fragmenter from fragmentretro.retrosynthesis import Retrosynthesis from fragmentretro.solutions import RetrosynthesisSolution from fragmentretro.typing import CombType, SolutionType from fragmentretro.utils.helpers import sort_by_heavy_atoms +from fragmentretro.utils.logging_config import logger class GuiController: diff --git a/src/fragmentretro/app/gui/layout.py b/src/fragmentretro/app/gui/layout.py index c77e4b8..77d99d2 100644 --- a/src/fragmentretro/app/gui/layout.py +++ b/src/fragmentretro/app/gui/layout.py @@ -1,5 +1,6 @@ import ipywidgets as widgets -from app.gui.widgets import ( + +from fragmentretro.app.gui.widgets import ( core_factor_input, display_button, file_path_input, diff --git a/src/fragmentretro/app/interface.py b/src/fragmentretro/app/interface.py index 9fc1cf0..3803a47 100644 --- a/src/fragmentretro/app/interface.py +++ b/src/fragmentretro/app/interface.py @@ -1,9 +1,10 @@ -from app.gui.controller import GuiController -from app.gui.layout import gui_layout -from app.gui.state import AppState -from app.gui.widgets import target_smiles_input from IPython.display import display +from fragmentretro.app.gui.controller import GuiController +from fragmentretro.app.gui.layout import gui_layout +from fragmentretro.app.gui.state import AppState +from fragmentretro.app.gui.widgets import target_smiles_input + # --- Main Function to Display GUI --- def display_gui(smiles: str | None = None) -> None: From c0d5694705db8311e054223aeb958f40b6282980 Mon Sep 17 00:00:00 2001 From: randyshee Date: Sat, 3 May 2025 20:34:24 -0400 Subject: [PATCH 23/24] FIX: change some logger to debug --- src/fragmentretro/fragmenter_base.py | 16 ++++++++-------- src/fragmentretro/retrosynthesis.py | 16 ++++++++-------- src/fragmentretro/solutions.py | 6 +++--- src/fragmentretro/substructure_matcher.py | 6 +++--- src/fragmentretro/utils/filter_compound.py | 10 +++++----- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/fragmentretro/fragmenter_base.py b/src/fragmentretro/fragmenter_base.py index 6d838d3..b021da9 100644 --- a/src/fragmentretro/fragmenter_base.py +++ b/src/fragmentretro/fragmenter_base.py @@ -134,17 +134,17 @@ def visualize( plt.axis("off") plt.show() - logger.info("[Fragmenter] \nNode data:") + logger.debug("[Fragmenter] \nNode data:") for node in self.fragment_graph.nodes(): - logger.info(f"[Fragmenter] \nNode {node}:") - logger.info(f"[Fragmenter] SMILES: {self.fragment_graph.nodes[node]['smiles']}") - logger.info(f"[Fragmenter] Atom indices: {self.fragment_graph.nodes[node]['atom_indices']}") + logger.debug(f"[Fragmenter] \nNode {node}:") + logger.debug(f"[Fragmenter] SMILES: {self.fragment_graph.nodes[node]['smiles']}") + logger.debug(f"[Fragmenter] Atom indices: {self.fragment_graph.nodes[node]['atom_indices']}") - logger.info("[Fragmenter] \nEdge data:") + logger.debug("[Fragmenter] \nEdge data:") for u, v, data in self.fragment_graph.edges(data=True): - logger.info(f"[Fragmenter] \nEdge {data['edge_index']} ({u}-{v}):") - logger.info(f"[Fragmenter] Bond type: {data['bond_type']}") - logger.info(f"[Fragmenter] Atoms: {data['atoms']}") + logger.debug(f"[Fragmenter] \nEdge {data['edge_index']} ({u}-{v}):") + logger.debug(f"[Fragmenter] Bond type: {data['bond_type']}") + logger.debug(f"[Fragmenter] Atoms: {data['atoms']}") def get_length_n_combinations(self, n: int) -> set[CombType]: """ diff --git a/src/fragmentretro/retrosynthesis.py b/src/fragmentretro/retrosynthesis.py index 25b72ea..febc04c 100644 --- a/src/fragmentretro/retrosynthesis.py +++ b/src/fragmentretro/retrosynthesis.py @@ -145,7 +145,7 @@ def _get_possible_BBs_for_comb(self, comb: CombType) -> BBsType: return filtered_BBs else: possible_BBs = self._get_possible_BBs_for_comb_no_filter(comb) - logger.info( + logger.debug( f"[Retrosynthesis] Number of possible BBs (when no filter) for {comb_smiles}: {len(possible_BBs)}" ) return possible_BBs.intersection(filtered_BBs) @@ -175,7 +175,7 @@ def _retro_stage(self, stage: int) -> tuple[int, int]: combs = list(self.fragmenter.get_length_n_combinations_from_last_stage(self.last_stage_combs)) self.last_stage_combs = combs - logger.info(f"[Retrosynthesis] Stage {stage}: {len(combs)} combinations") + logger.debug(f"[Retrosynthesis] Stage {stage}: {len(combs)} combinations") # check invalid comb and filter out effective comb effective_combs, invalid_combs = [], [] for comb in combs: @@ -184,14 +184,14 @@ def _retro_stage(self, stage: int) -> tuple[int, int]: else: invalid_combs.append(comb) self.invalid_combinations_dict[stage] = invalid_combs - logger.info(f"[Retrosynthesis] Stage {stage}: {len(effective_combs)} effective combinations") + logger.debug(f"[Retrosynthesis] Stage {stage}: {len(effective_combs)} effective combinations") for comb in effective_combs: fragment_smiles = self.fragmenter.get_combination_smiles(comb) fragment_smiles_without_indices = remove_indices_before_dummy(fragment_smiles) # get building blocks for comb if fragment_smiles_without_indices in self.fragment_bbs_dict: - logger.info( + logger.debug( f"[Retrosynthesis] Fragment {fragment_smiles} ( {fragment_smiles_without_indices} ) already processed" ) previous_comb, valid_BBs = self.fragment_bbs_dict[fragment_smiles_without_indices] @@ -199,7 +199,7 @@ def _retro_stage(self, stage: int) -> tuple[int, int]: self.comb_filter_indices_dict[comb] = self.comb_filter_indices_dict[previous_comb] else: possible_comb_BBs = self._get_possible_BBs_for_comb(comb) - logger.info(f"[Retrosynthesis] Number of possible BBs for {fragment_smiles}: {len(possible_comb_BBs)}") + logger.debug(f"[Retrosynthesis] Number of possible BBs for {fragment_smiles}: {len(possible_comb_BBs)}") comb_matcher = SubstructureMatcher( possible_comb_BBs, parallelize=self.parallelize, @@ -217,8 +217,8 @@ def _retro_stage(self, stage: int) -> tuple[int, int]: self.invalid_combinations_dict[stage].append(comb) stage_valid_count = len(self.valid_combinations_dict[stage]) stage_invalid_count = len(self.invalid_combinations_dict[stage]) - logger.info(f"[Retrosynthesis] Stage {stage}: {stage_valid_count} valid combinations") - logger.info(f"[Retrosynthesis] Stage {stage}: {stage_invalid_count} invalid combinations") + logger.debug(f"[Retrosynthesis] Stage {stage}: {stage_valid_count} valid combinations") + logger.debug(f"[Retrosynthesis] Stage {stage}: {stage_invalid_count} invalid combinations") return stage_valid_count, stage_invalid_count def fragment_retrosynthesis(self) -> StageCombDictType: @@ -236,7 +236,7 @@ def fragment_retrosynthesis(self) -> StageCombDictType: for stage in range(1, self.num_fragments + 1): stage_valid_count, stage_invalid_count = self._retro_stage(stage) if stage_valid_count == 0 or (stage == 1 and stage_invalid_count > 0): - logger.info(f"[Retrosynthesis] Stopped at stage {stage}") + logger.debug(f"[Retrosynthesis] Stopped at stage {stage}") break if self.use_filter: # save memory diff --git a/src/fragmentretro/solutions.py b/src/fragmentretro/solutions.py index fbd0f13..d949843 100644 --- a/src/fragmentretro/solutions.py +++ b/src/fragmentretro/solutions.py @@ -90,7 +90,7 @@ def get_solutions( solution, remaining_fragments, i + 1, valid_combinations, all_solutions ) if solution_cap and len(all_solutions) >= solution_cap: - logger.info(f"[RetrosynthesisSolution] Solution count capped at {solution_cap}") + logger.debug(f"[RetrosynthesisSolution] Solution count capped at {solution_cap}") return all_solutions[:solution_cap] return all_solutions @@ -137,9 +137,9 @@ def visualize_solutions( """ all_img = [] for solution in solutions: - logger.info(f"[RetrosynthesisSolution] Solution: {solution}") + logger.debug(f"[RetrosynthesisSolution] Solution: {solution}") all_smiles = self.get_solution_smiles(solution) - logger.info(f"[RetrosynthesisSolution] SMILES: {all_smiles}") + logger.debug(f"[RetrosynthesisSolution] SMILES: {all_smiles}") # Convert SMILES to RDKit molecules mols = [Chem.MolFromSmiles(smiles) for smiles in all_smiles] # Draw molecules in a grid diff --git a/src/fragmentretro/substructure_matcher.py b/src/fragmentretro/substructure_matcher.py index 3552bfd..66040e2 100644 --- a/src/fragmentretro/substructure_matcher.py +++ b/src/fragmentretro/substructure_matcher.py @@ -175,9 +175,9 @@ def get_substructure_BBs(self, fragment: str) -> BBsType: Returns: Set of building block SMILES strings that the fragment matches. """ - logger.info(f"[SubstructureMatcher] Matching fragment {fragment} to building blocks") + logger.debug(f"[SubstructureMatcher] Matching fragment {fragment} to building blocks") if self.parallelize and len(self.BBs) >= self.num_cores * self.core_factor: - logger.info(f"[SubstructureMatcher] Using {self.num_cores} cores for parallel processing") + logger.debug(f"[SubstructureMatcher] Using {self.num_cores} cores for parallel processing") with Pool(processes=self.num_cores) as pool: results = pool.starmap( self.is_strict_substructure, [(fragment, bb, self.useChirality) for bb in self.BBs] @@ -189,5 +189,5 @@ def get_substructure_BBs(self, fragment: str) -> BBsType: strict_substructure_BBs = set( bb for bb in self.BBs if self.is_strict_substructure(fragment, bb, self.useChirality) ) - logger.info(f"[SubstructureMatcher] Found {len(strict_substructure_BBs)} matching building") + logger.debug(f"[SubstructureMatcher] Found {len(strict_substructure_BBs)} matching building") return strict_substructure_BBs diff --git a/src/fragmentretro/utils/filter_compound.py b/src/fragmentretro/utils/filter_compound.py index ddf3c58..c5f0fee 100644 --- a/src/fragmentretro/utils/filter_compound.py +++ b/src/fragmentretro/utils/filter_compound.py @@ -95,7 +95,7 @@ def __init__(self, mol_properties_path: Path, fpSize: int = 2048): def _load_mol_properties(self) -> None: """Loads molecular properties from the JSON file.""" - logger.info("[CompoundFilter] Loading mol properties") + logger.debug("[CompoundFilter] Loading mol properties") with open(self.mol_properties_path) as f: mol_properties_list = json.load(f) @@ -105,7 +105,7 @@ def _load_mol_properties(self) -> None: self.num_rings_list = [props["num_rings"] for props in mol_properties_list] self.pfp_len_list = [len(props["pfp"]) for props in mol_properties_list] self.pfp_list = [props["pfp"] for props in mol_properties_list] - logger.info("[CompoundFilter] Finished loading mol properties") + logger.debug("[CompoundFilter] Finished loading mol properties") def _create_numpy_arrays(self) -> None: """Creates NumPy arrays for faster filtering.""" @@ -137,7 +137,7 @@ def filter_compounds(self, smiles: str, prefiltered_indices: FilterIndicesType | print(f"Invalid SMILES: {e}") return [] - logger.info(f"[CompoundFilter] Filtering BBs for {no_dummy_smiles} ( {smiles} )") + logger.debug(f"[CompoundFilter] Filtering BBs for {no_dummy_smiles} ( {smiles} )") num_heavy_atoms = mol_properties["num_heavy_atoms"] num_rings = mol_properties["num_rings"] @@ -165,9 +165,9 @@ def filter_compounds(self, smiles: str, prefiltered_indices: FilterIndicesType | ].tolist() if prefiltered_indices is None: - logger.info(f"[CompoundFilter] Originally {self.len_BBs} BBs, filtered down to {len(filtered_indices)}") + logger.debug(f"[CompoundFilter] Originally {self.len_BBs} BBs, filtered down to {len(filtered_indices)}") else: - logger.info( + logger.debug( f"[CompoundFilter] Originally {len(prefiltered_indices)} BBs, filtered down to {len(filtered_indices)}" ) From 9a489f18c23b8668e963b874b366387d2641297f Mon Sep 17 00:00:00 2001 From: randyshee Date: Sat, 3 May 2025 21:18:01 -0400 Subject: [PATCH 24/24] FIX: suppress rdkit log in rbrics --- src/fragmentretro/fragmentation/r_brics.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fragmentretro/fragmentation/r_brics.py b/src/fragmentretro/fragmentation/r_brics.py index b7ee1a0..d274977 100644 --- a/src/fragmentretro/fragmentation/r_brics.py +++ b/src/fragmentretro/fragmentation/r_brics.py @@ -47,11 +47,13 @@ import re from collections.abc import Generator -from rdkit import Chem +from rdkit import Chem, RDLogger from rdkit.Chem import rdChemReactions as Reactions from fragmentretro.exceptions import SmartsParsingError +RDLogger.DisableLog("rdApp.*") # Disable RDKit warning messages + type EnvironmentLabel = str type SmartsPattern = str type BondTypeSpecifier = str