', 'exec')
- exec(pyc, frame)
-
- # Fetch the base_class and form class based on their type in the
- # xml from designer
- form_class = frame['Ui_%s' % form_class]
- base_class = getattr(QtWidgets, widget_class)
-
- return form_class, base_class
diff --git a/winpython/_vendor/vendor.txt b/winpython/_vendor/vendor.txt
deleted file mode 100644
index 02c7ccc2..00000000
--- a/winpython/_vendor/vendor.txt
+++ /dev/null
@@ -1 +0,0 @@
-qtpy==2.0.0.dev0-20211211
diff --git a/winpython/associate.py b/winpython/associate.py
deleted file mode 100644
index 7ef6bc4e..00000000
--- a/winpython/associate.py
+++ /dev/null
@@ -1,375 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2012 Pierre Raybaut
-# Licensed under the terms of the MIT License
-# (see winpython/__init__.py for details)
-
-"""
-Register a Python distribution
-
-Created on Tue Aug 21 21:46:30 2012
-"""
-
-from __future__ import print_function
-
-import sys
-import os
-import os.path as osp
-from pathlib import Path
-import subprocess
-
-
-# Local imports
-from winpython.py3compat import winreg
-from winpython import utils
-
-KEY_C = r"Software\Classes\%s"
-KEY_C0 = KEY_C % r"Python.%sFile\shell"
-KEY_C1 = KEY_C % r"Python.%sFile\shell\%s"
-KEY_C2 = KEY_C1 + r"\command"
-KEY_DROP0 = KEY_C % r"Python.%sFile\shellex"
-KEY_DROP1 = KEY_C % r"Python.%sFile\shellex\DropHandler"
-KEY_I = KEY_C % r"Python.%sFile\DefaultIcon"
-KEY_D = KEY_C % r"Python.%sFile"
-EWI = "Edit with IDLE"
-EWS = "Edit with Spyder"
-
-KEY_S = r"Software\Python"
-KEY_S0 = KEY_S + r"\PythonCore"
-KEY_S1 = KEY_S0 + r"\%s"
-
-
-def _get_shortcut_data(target, current=True):
- wpgroup = utils.create_winpython_start_menu_folder(
- current=current
- )
- # wpdir = osp.join(target, os.pardir)
- wpdir = str(Path(target).parent)
- data = []
- for name in os.listdir(wpdir):
- bname, ext = osp.splitext(name)
- if ext == '.exe':
- data.append(
- (
- # osp.join(wpdir, name),
- str(Path(wpdir) / name),
- bname,
- # osp.join(wpgroup, bname),
- str(Path(wpgroup) / bname),
- )
- )
- return data
-
-
-def register(target, current=True):
- """Register a Python distribution in Windows registry"""
- root = (
- winreg.HKEY_CURRENT_USER
- if current
- else winreg.HKEY_LOCAL_MACHINE
- )
-
- # Extensions
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C % ".py"),
- "",
- 0,
- winreg.REG_SZ,
- "Python.File",
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C % ".pyw"),
- "",
- 0,
- winreg.REG_SZ,
- "Python.NoConFile",
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C % ".pyc"),
- "",
- 0,
- winreg.REG_SZ,
- "Python.CompiledFile",
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C % ".pyo"),
- "",
- 0,
- winreg.REG_SZ,
- "Python.CompiledFile",
- )
-
- # MIME types
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C % ".py"),
- "Content Type",
- 0,
- winreg.REG_SZ,
- "text/plain",
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C % ".pyw"),
- "Content Type",
- 0,
- winreg.REG_SZ,
- "text/plain",
- )
-
- # Verbs
- # python = osp.abspath(osp.join(target, 'python.exe'))
- python = osp.abspath(str(Path(target) / 'python.exe'))
- # pythonw = osp.abspath(osp.join(target, 'pythonw.exe'))
- pythonw = osp.abspath(str(Path(target) / 'pythonw.exe'))
- spyder = osp.abspath(
- # osp.join(target, os.pardir, 'Spyder.exe')
- str(Path(target).parent / 'Spyder.exe')
- )
- if not osp.isfile(spyder):
- spyder = '%s" "%s\Scripts\spyder' % (
- pythonw,
- target,
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C2 % ("", "open")),
- "",
- 0,
- winreg.REG_SZ,
- '"%s" "%%1" %%*' % python,
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C2 % ("NoCon", "open")),
- "",
- 0,
- winreg.REG_SZ,
- '"%s" "%%1" %%*' % pythonw,
- )
- winreg.SetValueEx(
- winreg.CreateKey(
- root, KEY_C2 % ("Compiled", "open")
- ),
- "",
- 0,
- winreg.REG_SZ,
- '"%s" "%%1" %%*' % python,
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C2 % ("", EWI)),
- "",
- 0,
- winreg.REG_SZ,
- '"%s" "%s\Lib\idlelib\idle.pyw" -n -e "%%1"'
- % (pythonw, target),
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C2 % ("NoCon", EWI)),
- "",
- 0,
- winreg.REG_SZ,
- '"%s" "%s\Lib\idlelib\idle.pyw" -n -e "%%1"'
- % (pythonw, target),
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C2 % ("", EWS)),
- "",
- 0,
- winreg.REG_SZ,
- '"%s" "%%1"' % spyder,
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_C2 % ("NoCon", EWS)),
- "",
- 0,
- winreg.REG_SZ,
- '"%s" "%%1"' % spyder,
- )
-
- # Drop support
- handler = "{60254CA5-953B-11CF-8C96-00AA00B8708C}"
- for ftype in ("", "NoCon", "Compiled"):
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_DROP1 % ftype),
- "",
- 0,
- winreg.REG_SZ,
- handler,
- )
- # Icons
- # dlls = osp.join(target, 'DLLs')
- dlls = str(Path(target) / 'DLLs')
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_I % ""),
- "",
- 0,
- winreg.REG_SZ,
- r'%s\py.ico' % dlls,
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_I % "NoCon"),
- "",
- 0,
- winreg.REG_SZ,
- r'%s\py.ico' % dlls,
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_I % "Compiled"),
- "",
- 0,
- winreg.REG_SZ,
- r'%s\pyc.ico' % dlls,
- )
-
- # Descriptions
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_D % ""),
- "",
- 0,
- winreg.REG_SZ,
- "Python File",
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_D % "NoCon"),
- "",
- 0,
- winreg.REG_SZ,
- "Python File (no console)",
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, KEY_D % "Compiled"),
- "",
- 0,
- winreg.REG_SZ,
- "Compiled Python File",
- )
-
- # PythonCore entries
- short_version = utils.get_python_infos(target)[0]
- long_version = utils.get_python_long_version(target)
- key_core = (KEY_S1 % short_version) + r'\%s'
- winreg.SetValueEx(
- winreg.CreateKey(root, key_core % 'InstallPath'),
- "",
- 0,
- winreg.REG_SZ,
- target,
- )
- winreg.SetValueEx(
- winreg.CreateKey(
- root, key_core % r'InstallPath\InstallGroup'
- ),
- "",
- 0,
- winreg.REG_SZ,
- "Python %s" % short_version,
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, key_core % 'Modules'),
- "",
- 0,
- winreg.REG_SZ,
- "",
- )
- winreg.SetValueEx(
- winreg.CreateKey(root, key_core % 'PythonPath'),
- "",
- 0,
- winreg.REG_SZ,
- r"%s\Lib;%s\DLLs" % (target, target),
- )
- winreg.SetValueEx(
- winreg.CreateKey(
- root,
- key_core % r'Help\Main Python Documentation',
- ),
- "",
- 0,
- winreg.REG_SZ,
- r"%s\Doc\python%s.chm" % (target, long_version),
- )
-
- # Create start menu entries for all WinPython launchers
- for path, desc, fname in _get_shortcut_data(
- target, current=current
- ):
- utils.create_shortcut(path, desc, fname)
-
-def unregister(target, current=True):
- """Unregister a Python distribution in Windows registry"""
- # Registry entries
- root = (
- winreg.HKEY_CURRENT_USER
- if current
- else winreg.HKEY_LOCAL_MACHINE
- )
- short_version = utils.get_python_infos(target)[0]
- key_core = (KEY_S1 % short_version) + r'\%s'
- for key in (
- # Drop support
- KEY_DROP1 % "",
- KEY_DROP1 % "NoCon",
- KEY_DROP1 % "Compiled",
- KEY_DROP0 % "",
- KEY_DROP0 % "NoCon",
- KEY_DROP0 % "Compiled",
- # Icons
- KEY_I % "NoCon",
- KEY_I % "Compiled",
- KEY_I % "",
- # Edit with IDLE
- KEY_C2 % ("", EWI),
- KEY_C2 % ("NoCon", EWI),
- KEY_C1 % ("", EWI),
- KEY_C1 % ("NoCon", EWI),
- # Edit with Spyder
- KEY_C2 % ("", EWS),
- KEY_C2 % ("NoCon", EWS),
- KEY_C1 % ("", EWS),
- KEY_C1 % ("NoCon", EWS),
- # Verbs
- KEY_C2 % ("", "open"),
- KEY_C2 % ("NoCon", "open"),
- KEY_C2 % ("Compiled", "open"),
- KEY_C1 % ("", "open"),
- KEY_C1 % ("NoCon", "open"),
- KEY_C1 % ("Compiled", "open"),
- KEY_C0 % "",
- KEY_C0 % "NoCon",
- KEY_C0 % "Compiled",
- # Descriptions
- KEY_D % "NoCon",
- KEY_D % "Compiled",
- KEY_D % "",
- # PythonCore
- key_core % r'InstallPath\InstallGroup',
- key_core % 'InstallPath',
- key_core % 'Modules',
- key_core % 'PythonPath',
- key_core % r'Help\Main Python Documentation',
- key_core % 'Help',
- KEY_S1 % short_version,
- KEY_S0,
- KEY_S,
- ):
- try:
- print(key)
- winreg.DeleteKey(root, key)
- except WindowsError:
- rootkey = (
- 'HKEY_CURRENT_USER'
- if current
- else 'HKEY_LOCAL_MACHINE'
- )
- print(
- r'Unable to remove %s\%s' % (rootkey, key),
- file=sys.stderr,
- )
- # Start menu shortcuts
- for path, desc, fname in _get_shortcut_data(
- target, current=current
- ):
- if osp.exists(fname):
- os.remove(fname)
-
-
-if __name__ == '__main__':
- register(sys.prefix)
- unregister(sys.prefix)
diff --git a/winpython/build_winpython.py b/winpython/build_winpython.py
new file mode 100644
index 00000000..940b285a
--- /dev/null
+++ b/winpython/build_winpython.py
@@ -0,0 +1,256 @@
+# build_winpython.py
+import os, sys, argparse, datetime, subprocess, shutil
+import logging
+
+from pathlib import Path
+from filecmp import cmp
+
+LOG_FORMAT = "%(asctime)s %(levelname)s: %(message)s"
+
+def setup_logging(log_file: Path):
+ """Initialize logging to both file and stdout."""
+ logging.basicConfig(
+ level=logging.INFO,
+ format=LOG_FORMAT,
+ handlers=[
+ logging.StreamHandler(sys.stdout),
+ logging.FileHandler(str(log_file), encoding="utf-8", mode='a')
+ ]
+ )
+
+def log_section(message: str):
+ logging.info("\n" + "-"*40)
+ logging.info(message)
+ logging.info("-"*40)
+
+def delete_folder_if_exists(folder: Path, check_flavor: str = ""):
+ check_last = folder.parent.name if not folder.is_dir() else folder.name
+ expected_name = "bu" + check_flavor
+ if folder.exists() and folder.is_dir() and check_last == expected_name:
+ logging.info(f"Removing old backup: {folder}")
+ folder_old = folder.with_suffix('.old')
+ if folder_old.exists():
+ shutil.rmtree(folder_old)
+ folder.rename(folder_old)
+ shutil.rmtree(folder_old)
+
+def run_command(cmd, shell=False, check=True):
+ logging.info(f"[RUNNING] {' '.join(cmd) if isinstance(cmd, list) else cmd}")
+ with subprocess.Popen(
+ cmd, shell=shell, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, universal_newlines=True
+ ) as proc:
+ for line in proc.stdout:
+ logging.info(line.rstrip())
+ if check and proc.wait() != 0:
+ raise subprocess.CalledProcessError(proc.returncode, cmd)
+
+def pip_install(python_exe: Path, req_file: str, constraints: str, find_links: str, label: str):
+ if req_file and Path(req_file).exists():
+ cmd = [
+ str(python_exe), "-m", "pip", "install",
+ "-r", req_file, "-c", constraints,
+ "--pre", "--no-index", f"--find-links={find_links}"
+ ]
+ log_section(f"Pip-install {label}")
+ run_command(cmd)
+ else:
+ log_section(f"No {label} specified/skipped")
+
+def patch_winpython(python_exe):
+ cmd = [
+ str(python_exe), "-c",
+ "from wppm import wppm; wppm.Distribution().patch_standard_packages('', to_movable=True)"
+ ]
+ run_command(cmd)
+
+def check_env_bat(winpydirbase: Path):
+ envbat = winpydirbase / "scripts" / "env.bat"
+ if not envbat.exists():
+ raise FileNotFoundError(f"Missing env.bat at {envbat}")
+
+def generate_lockfiles(target_python: Path, winpydirbase: Path, constraints: str, find_links: str, file_postfix: str):
+ pip_req = winpydirbase.parent / "requirement_temp.txt"
+ with subprocess.Popen([str(target_python), "-m", "pip", "freeze"], stdout=subprocess.PIPE) as proc:
+ packages = [l for l in proc.stdout if b"winpython" not in l]
+ pip_req.write_bytes(b"".join(packages))
+ # Lock to web and local (scaffolding)
+ for kind in ("", "local"):
+ out = winpydirbase.parent / f"pylock.{file_postfix}_{kind}.toml"
+ outreq = winpydirbase.parent / f"requir.{file_postfix}_{kind}.txt"
+ cmd = [str(target_python), "-m", "pip", "lock", "--no-deps", "-c", constraints]
+ if kind == "local":
+ cmd += ["--find-links", find_links]
+ cmd += ["-r", str(pip_req), "-o", str(out)]
+ run_command(cmd)
+ # Convert both locks to requirement.txt with hash256
+ cmd = [str(target_python), "-X", "utf8", "-c", f"from wppm import wheelhouse as wh; wh.pylock_to_req(r'{out}', r'{outreq}')"]
+ run_command(cmd)
+ # check equality
+ web, local = "", "local"
+ if not cmp(winpydirbase.parent / f"requir.{file_postfix}_{web}.txt", winpydirbase.parent / f"requir.{file_postfix}_{local}.txt"):
+ print("⚠️⚠️⚠️⚠️⚠️⚠️ ALARM ⚠️⚠️⚠️⚠️⚠️⚠️differences in ", winpydirbase.parent / f"requir.{file_postfix}_{web}.txt", winpydirbase.parent / f"requir.{file_postfix}_{local}.txt")
+ raise os.error
+ else:
+ print ("💖💖💖 match 💖💖💖 ok ",winpydirbase.parent / f"requir.{file_postfix}_{web}.txt", winpydirbase.parent / f"requir.{file_postfix}_{local}.txt")
+
+# --- Main Logic ---
+def run_make_py(build_python, winpydirbase, args):
+ from . import make
+ make.make_all(
+ args.release, args.release_level, basedir_wpy=winpydirbase,
+ verbose=True, flavor=args.flavor,
+ source_dirs=args.source_dirs, toolsdirs=args.tools_dirs
+ )
+
+def process_wheelhouse_requirements(target_python: Path, winpydirbase: Path,args: argparse.Namespace,file_postfix: str):
+ """
+ Handle installation and conversion of wheelhouse requirements.
+ """
+ wheelhousereq = Path(args.wheelhousereq)
+ kind = "local"
+ out = winpydirbase.parent / f"pylock.{file_postfix}_wheels{kind}.toml"
+ outreq = winpydirbase.parent / f"requir.{file_postfix}_wheels{kind}.txt"
+ if wheelhousereq.is_file():
+ # Generate pylock from wheelhousereq
+ cmd = [
+ str(target_python), "-m", "pip", "lock", "--no-index", "--trusted-host=None",
+ "--find-links", args.find_links, "-c", args.constraints, "-r", str(wheelhousereq),
+ "-o", str(out)
+ ]
+ run_command(cmd)
+ # Convert pylock to requirements with hash
+ pylock_to_req_cmd = [
+ str(target_python), "-X", "utf8", "-c",
+ f"from wppm import wheelhouse as wh; wh.pylock_to_req(r'{out}', r'{outreq}')"
+ ]
+ run_command(pylock_to_req_cmd, check=False)
+
+ kind = ""
+ outw = winpydirbase.parent / f"pylock.{file_postfix}_wheels{kind}.toml"
+ outreqw = winpydirbase.parent / f"requir.{file_postfix}_wheels{kind}.txt"
+ # Generate web pylock from local frozen hashes
+ web_lock_cmd = [
+ str(target_python), "-m", "pip", "lock", "--no-deps", "--require-hashes",
+ "-r", str(outreq), "-o", str(outw)
+ ]
+ run_command(web_lock_cmd)
+ pylock_to_req_cmd2 = [
+ str(target_python), "-X", "utf8", "-c",
+ f"from wppm import wheelhouse as wh; wh.pylock_to_req(r'{outw}', r'{outreqw}')"
+ ]
+ run_command(pylock_to_req_cmd2, check=False)
+
+ # Use wppm to download local from req made with web hashes
+ wheelhouse = winpydirbase / "wheelhouse" / "included.wheels"
+ wppm_cmd = [
+ str(target_python), "-X", "utf8", "-m", "wppm", str(out), "-ws", args.find_links,
+ "-wd", str(wheelhouse)
+ ]
+ run_command(wppm_cmd, check=False)
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--python-target', required=True, help='Target Python version, e.g. 311')
+ parser.add_argument('--release', default='', help='Release')
+ parser.add_argument('--flavor', default='', help='Build flavor')
+ parser.add_argument('--arch', default='64', help='Architecture')
+ parser.add_argument('--release-level', default='b1', help='Release level (e.g., b1, rc)')
+ parser.add_argument('--winpydirbase', required=True, help='Path to put environment')
+ parser.add_argument('--source_dirs', required=True, help='Path to directory with python zip')
+ parser.add_argument('--tools_dirs', required=True, help='Path to directory with python zip')
+ parser.add_argument('--buildenv', required=True, help='Path to build environment')
+ parser.add_argument('--constraints', default='constraints.txt', help='Constraints file')
+ parser.add_argument('--requirements', help='Main requirements.txt file')
+ parser.add_argument('--find-links', default='wheelhouse', help='Path to local wheelhouse')
+ parser.add_argument('--log-dir', default='WinPython_build_logs', help='Directory for logs')
+ parser.add_argument('--mandatory-req', help='Mandatory requirements file')
+ parser.add_argument('--pre-req', help='Pre requirements file')
+ parser.add_argument('--wheelhousereq', help='Wheelhouse requirements file')
+ parser.add_argument('--create-installer', default='', help='default installer to create')
+ args = parser.parse_args()
+
+ # compute paths (same as Step2)...
+ build_python = Path(args.buildenv) / "python.exe"
+ winpydirbase = Path(args.winpydirbase)
+ target_python = winpydirbase / "python" / "python.exe"
+
+ # Setup paths and logs
+ now = datetime.datetime.now()
+ log_dir = Path(args.log_dir)
+ log_dir.mkdir(exist_ok=True)
+ time_str = now.strftime("%Y-%m-%d_at_%H%M")
+ log_file = log_dir / f"build_{args.python_target}_{args.flavor}_{args.release_level}_{time_str}.txt"
+ setup_logging(log_file)
+
+ # Logs termination and version naming
+ z = Path(winpydirbase).name[(4+len(args.arch)):-len(args.release_level)]
+ tada = f"{z[:1]}_{z[1:3]}_{z[3]}_{args.release}"
+ winpyver2 = tada.replace('_', '.')
+ file_postfix = f"{args.arch}-{tada}{args.flavor}{args.release_level}"
+
+ log_section(f"Preparing build for Python {args.python_target} ({args.arch}-bit)")
+
+ log_section(f"🙏 Step 1: displace old {Path(winpydirbase)}")
+ delete_folder_if_exists(winpydirbase.parent, check_flavor=args.flavor) #bu{flavor]}
+
+ log_section(f"🙏 Step 2: make.py Python with {str(build_python)} at ({winpydirbase}")
+ run_make_py(str(build_python), winpydirbase, args)
+
+ check_env_bat(winpydirbase)
+
+ log_section("🙏 Step 3: install requirements")
+
+ for label, req in [
+ ("Mandatory", args.mandatory_req),
+ ("Pre", args.pre_req),
+ ("Main", args.requirements),
+ ]:
+ pip_install(target_python, req, args.constraints, args.find_links, label)
+
+ log_section("🙏 Step 4: Patch Winpython")
+ patch_winpython(target_python)
+
+ log_section(f"🙏 Step 5: install wheelhouse requirements {args.wheelhousereq}")
+ if args.wheelhousereq:
+ process_wheelhouse_requirements(target_python, winpydirbase, args, file_postfix)
+
+ log_section("🙏 Step 6: install lockfiles")
+ print(target_python, winpydirbase, args.constraints, args.find_links, file_postfix)
+ generate_lockfiles(target_python, winpydirbase, args.constraints, args.find_links, file_postfix)
+
+
+ log_section(f"🙏 Step 7: generate changelog")
+ mdn = f"WinPython{args.flavor}-{args.arch}bit-{winpyver2}.md"
+ out = f"WinPython{args.flavor}-{args.arch}bit-{winpyver2}_History.md"
+ changelog_dir = log_dir.parent/ "changelogs"
+
+ cmd = ["set", f"WINPYVER2={winpyver2}&", "set", f"WINPYFLAVOR={args.flavor}&",
+ "set", f"WINPYVER={winpyver2}{args.flavor}{args.release_level}&",
+ str(target_python), "-X", "utf8", "-c" ,
+ (
+ "from wppm import wppm;"
+ "result = wppm.Distribution().generate_package_index_markdown();"
+ f"open(r'{winpydirbase.parent / mdn}', 'w', encoding='utf-8').write(result)"
+ )]
+ run_command(cmd, shell=True)
+ shutil.copyfile (winpydirbase.parent / mdn, changelog_dir / mdn)
+
+ cmd = [str(target_python), "-X", "utf8", "-c",
+ (
+ "from wppm import diff;"
+ f"result = diff.compare_package_indexes('{winpyver2}', searchdir=r'{changelog_dir}', flavor=r'{args.flavor}', architecture={args.arch});"
+ f"open(r'{winpydirbase.parent / out}', 'w', encoding='utf-8').write(result)"
+ )]
+ run_command(cmd, check=False)
+ shutil.copyfile (winpydirbase.parent / out, changelog_dir / out)
+
+ if args.create_installer != "":
+ log_section("🙏 Step 8: Create Installer")
+ stem = f"WinPython{args.arch}-{winpyver2}{args.flavor}{args.release_level}"
+ cmd = [str(target_python), "-c",
+ f"from wppm import utils; utils.command_installer_7zip(r'{winpydirbase}', r'{winpydirbase.parent}', r'{stem}', r'{args.create_installer}')" ]
+ run_command(cmd, check=False)
+
+if __name__ == '__main__':
+ main()
diff --git a/winpython/config.py b/winpython/config.py
deleted file mode 100644
index 95e10fcf..00000000
--- a/winpython/config.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2012 Pierre Raybaut
-# Licensed under the terms of the MIT License
-# (see winpython/__init__.py for details)
-
-"""
-WinPython utilities configuration
-
-Created on Wed Aug 29 12:23:19 2012
-"""
-
-import sys
-import os.path as osp
-from pathlib import Path
-
-def get_module_path(modname):
- """Return module *modname* base path"""
- return osp.abspath(
- osp.dirname(sys.modules[modname].__file__)
- )
-
-
-def get_module_data_path(
- modname, relpath=None, attr_name='DATAPATH'
-):
- """Return module *modname* data path
- Note: relpath is ignored if module has an attribute named *attr_name*
-
- Handles py2exe/cx_Freeze distributions"""
- datapath = getattr(sys.modules[modname], attr_name, '')
- if datapath:
- return datapath
- else:
- datapath = get_module_path(modname)
- # parentdir = osp.join(datapath, osp.pardir)
- parentdir = str(Path(datapath).parent)
- if osp.isfile(parentdir):
- # Parent directory is not a directory but the 'library.zip' file:
- # this is either a py2exe or a cx_Freeze distribution
- datapath = osp.abspath(
- # osp.join(
- # osp.join(parentdir, osp.pardir), modname
- # )
- str(Path(parentdir).parent / modname)
- )
- if relpath is not None:
- datapath = osp.abspath(
- # osp.join(datapath, relpath)
- str(Path(datapath) / relpath)
- )
- return datapath
-
-
-DATA_PATH = get_module_data_path(
- 'winpython', relpath='data'
-)
-IMAGE_PATH = get_module_data_path(
- 'winpython', relpath='images'
-)
diff --git a/winpython/controlpanel.py b/winpython/controlpanel.py
deleted file mode 100644
index 13bdf2ae..00000000
--- a/winpython/controlpanel.py
+++ /dev/null
@@ -1,1011 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2012 Pierre Raybaut
-# Licensed under the terms of the MIT License
-# (see winpython/__init__.py for details)
-
-"""
-WinPython Package Manager GUI
-
-Created on Mon Aug 13 11:40:01 2012
-"""
-
-import os.path as osp
-from pathlib import Path
-import os
-import sys
-import platform
-import locale
-
-# winpython.qt becomes winpython._vendor.qtpy
-from winpython._vendor.qtpy.QtWidgets import (
- QApplication,
- QMainWindow,
- QWidget,
- QLineEdit,
- QHBoxLayout,
- QVBoxLayout,
- QMessageBox,
- QAbstractItemView,
- QProgressDialog,
- QTableView,
- QPushButton,
- QLabel,
- QTabWidget,
- QToolTip,
-)
-
-from winpython._vendor.qtpy.QtGui import (
- QColor,
- QDesktopServices,
-)
-
-from winpython._vendor.qtpy.QtCore import (
- Qt,
- QAbstractTableModel,
- QModelIndex,
- Signal,
- QThread,
- QTimer,
- QUrl,
-)
-from winpython._vendor.qtpy.compat import (
- to_qvariant,
- getopenfilenames,
- getexistingdirectory,
-)
-import winpython._vendor.qtpy
-
-from winpython.qthelpers import (
- get_icon,
- add_actions,
- create_action,
- keybinding,
- get_std_icon,
- action2button,
- mimedata2url,
-)
-
-# Local imports
-from winpython import __version__, __project_url__
-from winpython import wppm, associate, utils
-from winpython.py3compat import getcwd, to_text_string
-
-
-COLUMNS = ACTION, CHECK, NAME, VERSION, DESCRIPTION = list(
- range(5)
-)
-
-
-class PackagesModel(QAbstractTableModel):
- # Signals after PyQt4 old SIGNAL removal
- dataChanged = Signal(QModelIndex, QModelIndex)
-
- def __init__(self):
- QAbstractTableModel.__init__(self)
- self.packages = []
- self.checked = set()
- self.actions = {}
-
- def sortByName(self):
- self.packages = sorted(
- self.packages, key=lambda x: x.name
- )
- self.reset()
-
- def flags(self, index):
- if not index.isValid():
- return Qt.ItemIsEnabled
- column = index.column()
- if column in (NAME, VERSION, ACTION, DESCRIPTION):
- return Qt.ItemFlags(
- QAbstractTableModel.flags(self, index)
- )
- else:
- return Qt.ItemFlags(
- QAbstractTableModel.flags(self, index)
- | Qt.ItemIsUserCheckable
- | Qt.ItemIsEditable
- )
-
- def data(self, index, role=Qt.DisplayRole):
- if not index.isValid() or not (
- 0 <= index.row() < len(self.packages)
- ):
- return to_qvariant()
- package = self.packages[index.row()]
- column = index.column()
- if role == Qt.CheckStateRole and column == CHECK:
- return int(package in self.checked)
- elif role == Qt.DisplayRole:
- if column == NAME:
- return to_qvariant(package.name)
- elif column == VERSION:
- return to_qvariant(package.version)
- elif column == ACTION:
- action = self.actions.get(package)
- if action is not None:
- return to_qvariant(action)
- elif column == DESCRIPTION:
- return to_qvariant(package.description)
- elif role == Qt.TextAlignmentRole:
- if column == ACTION:
- return to_qvariant(
- int(Qt.AlignRight | Qt.AlignVCenter)
- )
- else:
- return to_qvariant(
- int(Qt.AlignLeft | Qt.AlignVCenter)
- )
- elif role == Qt.BackgroundColorRole:
- if package in self.checked:
- color = QColor(Qt.darkGreen)
- color.setAlphaF(0.1)
- return to_qvariant(color)
- else:
- color = QColor(Qt.lightGray)
- color.setAlphaF(0.3)
- return to_qvariant(color)
- return to_qvariant()
-
- def headerData(
- self, section, orientation, role=Qt.DisplayRole
- ):
- if role == Qt.TextAlignmentRole:
- if orientation == Qt.Horizontal:
- return to_qvariant(
- int(Qt.AlignHCenter | Qt.AlignVCenter)
- )
- return to_qvariant(
- int(Qt.AlignRight | Qt.AlignVCenter)
- )
- if role != Qt.DisplayRole:
- return to_qvariant()
- if orientation == Qt.Horizontal:
- if section == NAME:
- return to_qvariant("Name")
- elif section == VERSION:
- return to_qvariant("Version")
- elif section == ACTION:
- return to_qvariant("Action")
- elif section == DESCRIPTION:
- return to_qvariant("Description")
- return to_qvariant()
-
- def rowCount(self, index=QModelIndex()):
- return len(self.packages)
-
- def columnCount(self, index=QModelIndex()):
- return len(COLUMNS)
-
- def setData(self, index, value, role=Qt.EditRole):
- if (
- index.isValid()
- and 0 <= index.row() < len(self.packages)
- and role == Qt.CheckStateRole
- ):
- package = self.packages[index.row()]
- if package in self.checked:
- self.checked.remove(package)
- else:
- self.checked.add(package)
- # PyQt4 old SIGNAL: self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
- # PyQt4 old SIGNAL: index, index)
- self.dataChanged.emit(index, index)
- return True
- return False
-
-
-INSTALL_ACTION = 'Install'
-REPAIR_ACTION = 'Repair (reinstall)'
-NO_REPAIR_ACTION = 'None (Already installed)'
-UPGRADE_ACTION = 'Upgrade from v'
-NONE_ACTION = '-'
-
-
-class PackagesTable(QTableView):
- # Signals after PyQt4 old SIGNAL removal, to be emitted after package_added event
- package_added = Signal()
-
- def __init__(self, parent, process, winname):
- QTableView.__init__(self, parent)
- assert process in ('install', 'uninstall')
- self.process = process
- self.model = PackagesModel()
- self.setModel(self.model)
- self.winname = winname
- self.repair = False
- self.resizeColumnToContents(0)
- self.setAcceptDrops(process == 'install')
- if process == 'uninstall':
- self.hideColumn(0)
- self.distribution = None
-
- self.setSelectionBehavior(
- QAbstractItemView.SelectRows
- )
- self.verticalHeader().hide()
- self.setShowGrid(False)
-
- def reset_model(self):
- # self.model.reset() is deprecated in Qt5
- self.model.beginResetModel()
- self.model.endResetModel()
- self.horizontalHeader().setStretchLastSection(True)
- for colnb in (ACTION, CHECK, NAME, VERSION):
- self.resizeColumnToContents(colnb)
-
- def get_selected_packages(self):
- """Return selected packages"""
- return [
- pack
- for pack in self.model.packages
- if pack in self.model.checked
- ]
-
- def add_packages(self, fnames):
- """Add packages"""
- notsupported = []
- notcompatible = []
- dist = self.distribution
- for fname in fnames:
- bname = osp.basename(fname)
- try:
- package = wppm.Package(fname)
- if package.is_compatible_with(dist):
- self.add_package(package)
- else:
- notcompatible.append(bname)
- except NotImplementedError:
- notsupported.append(bname)
- # PyQt4 old SIGNAL: self.emit(SIGNAL('package_added()'))
- self.package_added.emit()
- if notsupported:
- QMessageBox.warning(
- self,
- "Warning",
- "The following packages filenaming are not "
- "recognized by %s:\n\n%s"
- % (self.winname, "
".join(notsupported)),
- QMessageBox.Ok,
- )
- if notcompatible:
- QMessageBox.warning(
- self,
- "Warning",
- "The following packages "
- "are not compatible with "
- "Python %s %dbit:\n\n%s"
- % (
- dist.version,
- dist.architecture,
- "
".join(notcompatible),
- ),
- QMessageBox.Ok,
- )
-
- def add_package(self, package):
- for pack in self.model.packages:
- if pack.name == package.name:
- return
- self.model.packages.append(package)
- self.model.packages.sort(key=lambda x: x.name)
- self.model.checked.add(package)
- self.reset_model()
-
- def remove_package(self, package):
- self.model.packages = [
- pack
- for pack in self.model.packages
- if pack.fname != package.fname
- ]
- if package in self.model.checked:
- self.model.checked.remove(package)
- if package in self.model.actions:
- self.model.actions.pop(package)
- self.reset_model()
-
- def refresh_distribution(self, dist):
- self.distribution = dist
- if self.process == 'install':
- for package in self.model.packages:
- pack = dist.find_package(package.name)
- if pack is None:
- action = INSTALL_ACTION
- elif pack.version == package.version:
- if self.repair:
- action = REPAIR_ACTION
- else:
- action = NO_REPAIR_ACTION
- else:
- action = UPGRADE_ACTION + pack.version
- self.model.actions[package] = action
- else:
- self.model.packages = (
- self.distribution.get_installed_packages()
- )
- for package in self.model.packages:
- self.model.actions[package] = NONE_ACTION
- self.reset_model()
-
- def select_all(self):
- allpk = set(self.model.packages)
- if self.model.checked == allpk:
- self.model.checked = set()
- else:
- self.model.checked = allpk
- self.model.reset()
-
- def dragMoveEvent(self, event):
- """Reimplement Qt method, just to avoid default drag'n drop
- implementation of QTableView to handle events"""
- event.acceptProposedAction()
-
- def dragEnterEvent(self, event):
- """Reimplement Qt method
- Inform Qt about the types of data that the widget accepts"""
- source = event.mimeData()
- if source.hasUrls() and mimedata2url(source):
- event.acceptProposedAction()
-
- def dropEvent(self, event):
- """Reimplement Qt method
- Unpack dropped data and handle it"""
- source = event.mimeData()
- fnames = [
- path
- for path in mimedata2url(source)
- if osp.isfile(path)
- ]
- self.add_packages(fnames)
- event.acceptProposedAction()
-
-
-class DistributionSelector(QWidget):
- """Python distribution selector widget"""
-
- TITLE = 'Select a Python distribution path'
-
- # Signals after PyQt4 old SIGNAL removal
- selected_distribution = Signal(str)
-
- def __init__(self, parent):
- super(DistributionSelector, self).__init__(parent)
- self.browse_btn = None
- self.label = None
- self.line_edit = None
- self.setup_widget()
-
- def set_distribution(self, path):
- """Set distribution directory"""
- self.line_edit.setText(path)
-
- def setup_widget(self):
- """Setup workspace selector widget"""
- self.label = QLabel()
- self.line_edit = QLineEdit()
- self.line_edit.setAlignment(Qt.AlignRight)
- self.line_edit.setReadOnly(True)
- # self.line_edit.setDisabled(True)
- self.browse_btn = QPushButton(
- get_std_icon('DirOpenIcon'), "", self
- )
- self.browse_btn.setToolTip(self.TITLE)
- # PyQt4 old SIGNAL:self.connect(self.browse_btn, SIGNAL("clicked()"),
- # PyQt4 old SIGNAL: self.select_directory)
- self.browse_btn.clicked.connect(
- self.select_directory
- )
- layout = QHBoxLayout()
- layout.addWidget(self.label)
- layout.addWidget(self.line_edit)
- layout.addWidget(self.browse_btn)
- layout.setContentsMargins(0, 0, 0, 0)
- self.setLayout(layout)
-
- def select_directory(self):
- """Select directory"""
- basedir = to_text_string(self.line_edit.text())
- if not osp.isdir(basedir):
- basedir = getcwd()
- while True:
- directory = getexistingdirectory(
- self, self.TITLE, basedir
- )
- if not directory:
- break
- if not utils.is_python_distribution(directory):
- QMessageBox.warning(
- self,
- self.TITLE,
- "The following directory is not a Python distribution.",
- QMessageBox.Ok,
- )
- basedir = directory
- continue
- directory = osp.abspath(osp.normpath(directory))
- self.set_distribution(directory)
- # PyQt4 old SIGNAL: self.emit(SIGNAL('selected_distribution(QString)'), directory)
- self.selected_distribution.emit(directory)
- break
-
-
-class Thread(QThread):
- """Installation/Uninstallation thread"""
-
- def __init__(self, parent):
- QThread.__init__(self, parent)
- self.callback = None
- self.error = None
-
- def run(self):
- try:
- self.callback()
- except Exception as error:
- error_str = str(error)
- fs_encoding = (
- sys.getfilesystemencoding()
- or locale.getpreferredencoding()
- )
- try:
- error_str = error_str.decode(fs_encoding)
- except (
- UnicodeError,
- TypeError,
- AttributeError,
- ):
- pass
- self.error = error_str
-
-
-def python_distribution_infos():
- """Return Python distribution infos (not selected distribution but
- the one used to run this script)"""
- winpyver = os.environ.get('WINPYVER')
- if winpyver is None:
- return 'Unknown Python distribution'
- else:
- return 'WinPython ' + winpyver
-
-
-class PMWindow(QMainWindow):
- NAME = 'WinPython Control Panel'
-
- def __init__(self):
- QMainWindow.__init__(self)
- self.setAttribute(Qt.WA_DeleteOnClose)
-
- self.distribution = None
-
- self.tabwidget = None
- self.selector = None
- self.table = None
- self.untable = None
-
- self.basedir = None
-
- self.select_all_action = None
- self.install_action = None
- self.uninstall_action = None
- self.remove_action = None
- self.packages_icon = get_std_icon(
- 'FileDialogContentsView'
- )
-
- self.setup_window()
-
- def _add_table(self, table, title, icon):
- """Add table tab to main tab widget, return button layout"""
- widget = QWidget()
- tabvlayout = QVBoxLayout()
- widget.setLayout(tabvlayout)
- tabvlayout.addWidget(table)
- btn_layout = QHBoxLayout()
- tabvlayout.addLayout(btn_layout)
- self.tabwidget.addTab(widget, icon, title)
- return btn_layout
-
- def setup_window(self):
- """Setup main window"""
- self.setWindowTitle(self.NAME)
- self.setWindowIcon(get_icon('winpython.svg'))
-
- self.selector = DistributionSelector(self)
- # PyQt4 old SIGNAL: self.connect(self.selector, SIGNAL('selected_distribution(QString)'),
- # PyQt4 old SIGNAL: self.distribution_changed)
- self.selector.selected_distribution.connect(
- self.distribution_changed
- )
-
- self.table = PackagesTable(
- self, 'install', self.NAME
- )
- # PyQt4 old SIGNAL:self.connect(self.table, SIGNAL('package_added()'),
- # PyQt4 old SIGNAL: self.refresh_install_button)
- self.table.package_added.connect(
- self.refresh_install_button
- )
-
- # PyQt4 old SIGNAL: self.connect(self.table, SIGNAL("clicked(QModelIndex)"),
- # PyQt4 old SIGNAL: lambda index: self.refresh_install_button())
- self.table.clicked.connect(
- lambda index: self.refresh_install_button()
- )
-
- self.untable = PackagesTable(
- self, 'uninstall', self.NAME
- )
- # PyQt4 old SIGNAL:self.connect(self.untable, SIGNAL("clicked(QModelIndex)"),
- # PyQt4 old SIGNAL: lambda index: self.refresh_uninstall_button())
- self.untable.clicked.connect(
- lambda index: self.refresh_uninstall_button()
- )
-
- self.selector.set_distribution(sys.prefix)
- self.distribution_changed(sys.prefix)
-
- self.tabwidget = QTabWidget()
- # PyQt4 old SIGNAL:self.connect(self.tabwidget, SIGNAL('currentChanged(int)'),
- # PyQt4 old SIGNAL: self.current_tab_changed)
- self.tabwidget.currentChanged.connect(
- self.current_tab_changed
- )
-
- btn_layout = self._add_table(
- self.table,
- "Install/upgrade packages",
- get_std_icon("ArrowDown"),
- )
- unbtn_layout = self._add_table(
- self.untable,
- "Uninstall packages",
- get_std_icon("DialogResetButton"),
- )
-
- central_widget = QWidget()
- vlayout = QVBoxLayout()
- vlayout.addWidget(self.selector)
- vlayout.addWidget(self.tabwidget)
- central_widget.setLayout(vlayout)
- self.setCentralWidget(central_widget)
-
- # Install tab
- add_action = create_action(
- self,
- "&Add packages...",
- icon=get_std_icon('DialogOpenButton'),
- triggered=self.add_packages,
- )
- self.remove_action = create_action(
- self,
- "Remove",
- shortcut=keybinding('Delete'),
- icon=get_std_icon('TrashIcon'),
- triggered=self.remove_packages,
- )
- self.remove_action.setEnabled(False)
- self.select_all_action = create_action(
- self,
- "(Un)Select all",
- shortcut=keybinding('SelectAll'),
- icon=get_std_icon('DialogYesButton'),
- triggered=self.table.select_all,
- )
- self.install_action = create_action(
- self,
- "&Install packages",
- icon=get_std_icon('DialogApplyButton'),
- triggered=lambda: self.process_packages(
- 'install'
- ),
- )
- self.install_action.setEnabled(False)
- quit_action = create_action(
- self,
- "&Quit",
- icon=get_std_icon('DialogCloseButton'),
- triggered=self.close,
- )
- packages_menu = self.menuBar().addMenu("&Packages")
- add_actions(
- packages_menu,
- [
- add_action,
- self.remove_action,
- self.install_action,
- None,
- quit_action,
- ],
- )
-
- # Uninstall tab
- self.uninstall_action = create_action(
- self,
- "&Uninstall packages",
- icon=get_std_icon('DialogCancelButton'),
- triggered=lambda: self.process_packages(
- 'uninstall'
- ),
- )
- self.uninstall_action.setEnabled(False)
-
- uninstall_btn = action2button(
- self.uninstall_action,
- autoraise=False,
- text_beside_icon=True,
- )
-
- # Option menu
- option_menu = self.menuBar().addMenu("&Options")
- repair_action = create_action(
- self,
- "Repair packages",
- tip="Reinstall packages even if version is unchanged",
- toggled=self.toggle_repair,
- )
- add_actions(option_menu, (repair_action,))
-
- # Advanced menu
- option_menu = self.menuBar().addMenu("&Advanced")
- register_action = create_action(
- self,
- "Register distribution...",
- tip="Register file extensions, icons and context menu",
- triggered=self.register_distribution,
- )
- unregister_action = create_action(
- self,
- "Unregister distribution...",
- tip="Unregister file extensions, icons and context menu",
- triggered=self.unregister_distribution,
- )
- open_console_action = create_action(
- self,
- "Open console here",
- triggered=lambda: os.startfile(
- self.command_prompt_path
- ),
- )
- open_console_action.setEnabled(
- osp.exists(self.command_prompt_path)
- )
- add_actions(
- option_menu,
- (
- register_action,
- unregister_action,
- None,
- open_console_action,
- ),
- )
-
- # # View menu
- # view_menu = self.menuBar().addMenu("&View")
- # popmenu = self.createPopupMenu()
- # add_actions(view_menu, popmenu.actions())
-
- # Help menu
- about_action = create_action(
- self,
- "About %s..." % self.NAME,
- icon=get_std_icon('MessageBoxInformation'),
- triggered=self.about,
- )
- report_action = create_action(
- self,
- "Report issue...",
- icon=get_icon('bug.png'),
- triggered=self.report_issue,
- )
- help_menu = self.menuBar().addMenu("?")
- add_actions(
- help_menu, [about_action, None, report_action]
- )
-
- # Status bar
- status = self.statusBar()
- status.setObjectName("StatusBar")
- status.showMessage(
- "Welcome to %s!" % self.NAME, 5000
- )
-
- # Button layouts
- for act in (
- add_action,
- self.remove_action,
- None,
- self.select_all_action,
- self.install_action,
- ):
- if act is None:
- btn_layout.addStretch()
- else:
- btn_layout.addWidget(
- action2button(
- act,
- autoraise=False,
- text_beside_icon=True,
- )
- )
- unbtn_layout.addWidget(uninstall_btn)
- unbtn_layout.addStretch()
-
- self.resize(400, 500)
-
- def current_tab_changed(self, index):
- """Current tab has just changed"""
- if index == 0:
- self.show_drop_tip()
-
- def refresh_install_button(self):
- """Refresh install button enable state"""
- self.table.refresh_distribution(self.distribution)
- self.install_action.setEnabled(
- len(self.get_packages_to_be_installed()) > 0
- )
- nbp = len(self.table.get_selected_packages())
- for act in (
- self.remove_action,
- self.select_all_action,
- ):
- act.setEnabled(nbp > 0)
- self.show_drop_tip()
-
- def show_drop_tip(self):
- """Show drop tip on install table"""
- callback = lambda: QToolTip.showText(
- self.table.mapToGlobal(self.table.pos()),
- 'Drop files here
'
- 'Executable installers (distutils) or source packages',
- self,
- )
- QTimer.singleShot(500, callback)
-
- def refresh_uninstall_button(self):
- """Refresh uninstall button enable state"""
- nbp = len(self.untable.get_selected_packages())
- self.uninstall_action.setEnabled(nbp > 0)
-
- def toggle_repair(self, state):
- """Toggle repair mode"""
- self.table.repair = state
- self.refresh_install_button()
-
- def register_distribution(self):
- """Register distribution"""
- answer = QMessageBox.warning(
- self,
- "Register distribution",
- "(experimental)",
- "This will associate file extensions, icons and "
- "Windows explorer's context menu entries ('Edit with IDLE', ...) "
- "with selected Python distribution in Windows registry. "
- "
Shortcuts for all WinPython launchers will be installed "
- "in WinPython Start menu group (replacing existing "
- "shortcuts)."
- "
Note: these actions are similar to those performed"
- "when installing old Pythons with the official installer before 'py' "
- "for Windows.
Do you want to continue?",
- QMessageBox.Yes | QMessageBox.No,
- )
- if answer == QMessageBox.Yes:
- associate.register(self.distribution.target)
-
- def unregister_distribution(self):
- """Unregister distribution"""
- answer = QMessageBox.warning(
- self,
- "Unregister distribution",
- "(experimental)",
- "This will remove file extensions associations, icons and "
- "Windows explorer's context menu entries ('Edit with IDLE', ...) "
- "with selected Python distribution in Windows registry. "
- "
Shortcuts for all WinPython launchers will be removed "
- "from WinPython Start menu group."
- "
Do you want to continue?",
- QMessageBox.Yes | QMessageBox.No,
- )
- if answer == QMessageBox.Yes:
- associate.unregister(self.distribution.target)
-
- @property
- def command_prompt_path(self):
- # return osp.join(
- # self.distribution.target,
- # osp.pardir,
- # "WinPython Command Prompt.exe",
- # )
- return str(Path(self.distribution.target).parent /
- "WinPython Command Prompt.exe")
-
- def distribution_changed(self, path):
- """Distribution path has just changed"""
- for package in self.table.model.packages:
- self.table.remove_package(package)
- dist = wppm.Distribution(to_text_string(path))
- self.table.refresh_distribution(dist)
- self.untable.refresh_distribution(dist)
- self.distribution = dist
- self.selector.label.setText(
- 'Python %s %dbit:'
- % (dist.version, dist.architecture)
- )
-
- def add_packages(self):
- """Add packages"""
- basedir = (
- self.basedir if self.basedir is not None else ''
- )
- fnames, _selfilter = getopenfilenames(
- parent=self,
- basedir=basedir,
- caption='Add packages',
- filters='*.exe *.zip *.tar.gz *.whl',
- )
- if fnames:
- self.basedir = osp.dirname(fnames[0])
- self.table.add_packages(fnames)
-
- def get_packages_to_be_installed(self):
- """Return packages to be installed"""
- return [
- pack
- for pack in self.table.get_selected_packages()
- if self.table.model.actions[pack]
- not in (NO_REPAIR_ACTION, NONE_ACTION)
- ]
-
- def remove_packages(self):
- """Remove selected packages"""
- for package in self.table.get_selected_packages():
- self.table.remove_package(package)
-
- def process_packages(self, action):
- """Install/uninstall packages"""
- if action == 'install':
- text, table = 'Installing', self.table
- if not self.get_packages_to_be_installed():
- return
- elif action == 'uninstall':
- text, table = 'Uninstalling', self.untable
- else:
- raise AssertionError
- packages = table.get_selected_packages()
- if not packages:
- return
- func = getattr(self.distribution, action)
- thread = Thread(self)
- for widget in self.children():
- if isinstance(widget, QWidget):
- widget.setEnabled(False)
- try:
- status = self.statusBar()
- except AttributeError:
- status = self.parent().statusBar()
- progress = QProgressDialog(
- self, Qt.FramelessWindowHint
- )
- progress.setMaximum(
- len(packages)
- ) # old vicious bug:len(packages)-1
- for index, package in enumerate(packages):
- progress.setValue(index)
- progress.setLabelText(
- "%s %s %s..."
- % (text, package.name, package.version)
- )
- QApplication.processEvents()
- if progress.wasCanceled():
- break
- if package in table.model.actions:
- try:
- thread.callback = lambda: func(package)
- thread.start()
- while thread.isRunning():
- QApplication.processEvents()
- if progress.wasCanceled():
- status.setEnabled(True)
- status.showMessage(
- "Cancelling operation..."
- )
- table.remove_package(package)
- error = thread.error
- except Exception as error:
- error = to_text_string(error)
- if error is not None:
- pstr = (
- package.name + ' ' + package.version
- )
- QMessageBox.critical(
- self,
- "Error",
- "Unable to %s %s"
- "
Error message:
%s"
- % (action, pstr, error),
- )
- progress.setValue(progress.maximum())
- status.clearMessage()
- for widget in self.children():
- if isinstance(widget, QWidget):
- widget.setEnabled(True)
- thread = None
- for table in (self.table, self.untable):
- table.refresh_distribution(self.distribution)
-
- def report_issue(self):
-
- issue_template = """\
-Python distribution: %s
-Control panel version: %s
-
-Python Version: %s
-Qt Version: %s, %s %s
-
-What steps will reproduce the problem?
-1.
-2.
-3.
-
-What is the expected output? What do you see instead?
-
-
-Please provide any additional information below.
-""" % (
- python_distribution_infos(),
- __version__,
- platform.python_version(),
- winpython._vendor.qtpy.QtCore.__version__,
- winpython.qt.API_NAME,
- winpython._vendor.qtpy.__version__,
- )
-
- url = QUrl("%s/issues/entry" % __project_url__)
- url.addQueryItem("comment", issue_template)
- QDesktopServices.openUrl(url)
-
- def about(self):
- """About this program"""
- QMessageBox.about(
- self,
- "About %s" % self.NAME,
- """%s %s
-
Package Manager and Advanced Tasks
- Copyright © 2012 Pierre Raybaut
-
Licensed under the terms of the MIT License
-
Created, developed and maintained by Pierre Raybaut
-
WinPython at Github.io: downloads, bug reports,
- discussions, etc.
- This program is executed by:
- %s
- Python %s, Qt %s, %s qtpy %s"""
- % (
- self.NAME,
- __version__,
- __project_url__,
- python_distribution_infos(),
- platform.python_version(),
- winpython._vendor.qtpy.QtCore.__version__,
- winpython._vendor.qtpy.API_NAME,
- winpython._vendor.qtpy.__version__,
- ),
- )
-
-
-def main(test=False):
- app = QApplication([])
- win = PMWindow()
- win.show()
- if test:
- return app, win
- else:
- app.exec_()
-
-
-def test():
- app, win = main(test=True)
- print(sys.modules)
- app.exec_()
-
-
-if __name__ == "__main__":
- main()
diff --git a/winpython/data/categories.ini b/winpython/data/categories.ini
deleted file mode 100644
index 3ca5fe29..00000000
--- a/winpython/data/categories.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[misc]
-description=Misc.
-
-[scientific]
-description=Scientific
-
-[util]
-description=Utilities
-
-[gui]
-description=Graphical User Interfaces
-
-[plot]
-description=2D and 3D Plotting
-
-[visu3d]
-description=3D Visualization
-
-[improc]
-description=Image Processing
-
-[dataproc]
-description=Data Processing
-
-[deploy]
-description=Installation/Deployment
-
-[docgen]
-description=Documentation Generation
-
diff --git a/winpython/data/packages.ini b/winpython/data/packages.ini
deleted file mode 100644
index e85b9506..00000000
--- a/winpython/data/packages.ini
+++ /dev/null
@@ -1,3408 +0,0 @@
-[absl-py]
-description = Abseil Python Common Libraries, see github.com/abseil/abseil-py.
-
-[adodbapi]
-description = A pure Python package implementing PEP 249 DB-API using Microsoft ADO.
-
-[affine]
-description = Matrices describing affine transformation of the plane.
-
-[aiodns]
-description = Simple DNS resolver for asyncio
-
-[aiofiles]
-description = File support for asyncio.
-
-[aiohttp]
-description = Async http client/server framework (asyncio)
-
-[aiosqlite]
-description = asyncio bridge to the standard sqlite3 module
-
-[alabaster]
-description = A configurable sidebar-enabled Sphinx theme
-
-[algopy]
-description = ALGOPY: Taylor Arithmetic Computation and Algorithmic Differentiation
-
-[altair]
-description = Altair: A declarative statistical visualization library for Python.
-
-[altair-data-server]
-description = A background data server for Altair charts.
-
-[altair-transform]
-description = A python engine for evaluating Altair transforms.
-
-[altair-widgets]
-description = Altair Widgets: An interactive visualization for statistical data for Python.
-
-[altgraph]
-description = Python graph (network) package
-
-[amqp]
-description = Low-level AMQP client for Python (fork of amqplib).
-
-[aniso8601]
-description = A library for parsing ISO 8601 strings.
-
-[ansiwrap]
-description = textwrap, but savvy to ANSI colors and styles
-
-[anyio]
-description = High level compatibility layer for multiple asynchronous event loop implementations
-
-[anyjson]
-description = Wraps the best available JSON implementation available in a common interface
-
-[apispec]
-description = A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification).
-
-[apistar]
-description = API documentation, validation, mocking, and clients.
-
-[appdirs]
-description = A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir".
-
-[apptools]
-description = application tools
-
-[argcomplete]
-description = Bash tab completion for argparse
-
-[argh]
-description = An unobtrusive argparse wrapper with natural syntax
-
-[args]
-description = Command Arguments for Humans.
-
-[asgiref]
-description = ASGI specs, helper code, and adapters
-
-[asciitree]
-description = Draws ASCII trees.
-
-[asn1crypto]
-description = Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP
-
-[asteval]
-description = Safe, minimalistic evaluator of python expression using ast module
-
-[astor]
-description = Read/rewrite/write Python ASTs
-
-[astroid]
-description = An abstract syntax tree for Python with inference support.
-
-[astroml]
-description = tools for machine learning and data mining in Astronomy
-
-[astropy]
-description = Community-developed python astronomy tools
-
-[astunparse]
-description = An AST unparser for Python
-
-[async-generator]
-description = Async generators and context managers for Python 3.5+
-
-[async-timeout]
-description = Timeout context manager for asyncio programs
-
-[atomicwrites]
-description = Atomic file writes.
-
-[attrs]
-description = Classes Without Boilerplate
-
-[autopep8]
-description = A tool that automatically formats Python code to conform to the PEP 8 style guide
-
-[azureml-dataprep]
-description = Azure ML Data Preparation SDK
-
-[babel]
-description = Internationalization utilities
-
-[backcall]
-description = Specifications for callback functions passed in to an API
-
-[backports-abc]
-description = A backport of recent additions to the 'collections.abc' module.
-
-[backports-shutil-get-terminal-size]
-description = A backport of the get_terminal_size function from Python 3.3's shutil.
-
-[backports-ssl-match-hostname]
-description = The ssl.match_hostname() function from Python 3.4
-
-[backports-weakref]
-description = Backport of new features in Python's weakref module
-
-[bandit]
-description = Security oriented static analyser for python code.
-
-[baresql]
-description = playing SQL directly on Python datas
-
-[base58]
-description = Base58 and Base58Check implementation
-
-[bcolz]
-description = columnar and compressed data containers.
-
-[bcrypt]
-description = Modern password hashing for your software and your servers
-
-[beautifulsoup4]
-description = Screen-scraping library
-
-[billiard]
-description = Python multiprocessing fork with improvements and bugfixes
-
-[binaryornot]
-description = Ultra-lightweight pure Python package to check if a file is binary or text.
-
-[bitarray]
-description = efficient arrays of booleans -- C extension
-
-[bkcharts]
-description = High level chart types built on top of Bokeh
-
-[black]
-description = The uncompromising code formatter.
-
-[blaze]
-description = Blaze
-
-[bleach]
-description = An easy safelist-based HTML-sanitizing tool.
-
-[blinker]
-description = Fast, simple object-to-object and broadcast signaling
-
-[blosc]
-description = Blosc data compressor
-
-[bloscpack]
-description = Command line interface to and serialization format for Blosc
-
-[bokeh]
-description = Interactive plots and applications in the browser from Python
-
-[boto3]
-description = The AWS SDK for Python
-
-[botocore]
-description = Low-level, data-driven core of boto 3.
-
-[bottle]
-description = Fast and simple WSGI-framework for small web-applications.
-
-[bottleneck]
-description = Fast NumPy array functions written in C
-
-[bqplot]
-description = Interactive plotting for the Jupyter notebook, using d3.js and ipywidgets.
-
-[branca]
-description = Generate complex HTML+JS pages with Python
-
-[brewer2mpl]
-description = Connect colorbrewer2.org color maps to Python and matplotlib
-
-[brotli]
-description = Python bindings for the Brotli compression library
-
-[cachetools]
-description = Extensible memoizing collections and decorators
-
-[cartopy]
-description = A cartographic python library with Matplotlib support for visualisation
-
-[castra]
-description = On-disk partitioned store
-
-[cchardet]
-description = cChardet is high speed universal character encoding detector.
-
-[cssselect]
-description = cssselect parses CSS3 Selectors and translates them to XPath 1.0
-
-[celery]
-description = Distributed Task Queue.
-
-[celerite]
-description = Scalable 1D Gaussian Processes
-
-[certifi]
-description = Python package for providing Mozilla's CA Bundle.
-
-[ceodbc]
-description = Python interface to ODBC
-
-[cffi]
-description = Foreign Function Interface for Python calling C code.
-
-[cftime]
-description = Time-handling functionality from netcdf4-python
-
-[chainer]
-description = A flexible framework of neural networks
-
-[chardet]
-description = Universal encoding detector for Python 2 and 3
-
-[click]
-description = Composable command line interface toolkit
-
-[click-default-group]
-description = Extends click.Group to invoke a command without explicit subcommand name
-
-[click-plugins]
-description = An extension module for click to enable registering CLI commands via setuptools entry-points.
-
-[cligj]
-description = Click params for commmand line interfaces to GeoJSON
-
-[clint]
-description = Python Command Line Interface Tools
-
-[cloudpickle]
-description = Extended pickling support for Python objects
-
-[clrmagic]
-description = IPython cell magic to use .NET languages
-
-[cmarkgfm]
-description = Minimal bindings to GitHub's fork of cmark
-
-[cntk]
-description = CNTK is an open-source, commercial-grade deep learning framework.
-
-[colorama]
-description = Cross-platform colored terminal text.
-
-[colorcet]
-description = Collection of perceptually uniform colormaps
-
-[coloredlogs]
-description = Colored terminal output for Python's logging module
-
-[comtypes]
-description = Pure Python COM package
-
-[commonmark]
-description = Python parser for the CommonMark Markdown spec
-
-[cookiecutter]
-description = A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template.
-
-[configobj]
-description = Config file reading, writing and validation.
-
-[configparser]
-description = Updated configparser from Python 3.8 for Python 2.6+.
-
-[contextily]
-description = Context geo-tiles in Python
-
-[contextlib2]
-description = Backports and enhancements for the contextlib module
-
-[contextvars]
-description = PEP 567 Backport
-
-[convertdate]
-description = Converts between Gregorian dates and other calendar systems.Calendars included: Baha'i, French Republican, Hebrew, Indian Civil, Islamic, ISO, Julian, Mayan and Persian.
-
-[corner]
-description = Make some beautiful corner plots of samples.
-
-[coverage]
-description = Code coverage measurement for Python
-
-[cryptography]
-description = cryptography is a package which provides cryptographic recipes and primitives to Python developers.
-
-[cupy]
-description = CuPy: NumPy-like API accelerated with CUDA
-
-[curio]
-description = Curio
-
-[cvxcanon]
-description = A low-level library to perform the matrix building step in cvxpy, a convex optimization modeling software.
-
-[cvxopt]
-description = Convex optimization package
-
-[cvxpy]
-description = A domain-specific language for modeling convex optimization problems in Python.
-
-[cx-freeze]
-description = create standalone executables from Python scripts
-
-[cycler]
-description = Composable style cycles
-
-[cymem]
-description = Manage calls to calloc/free through Cython
-
-[cyordereddict]
-description = Cython implementation of Python's collections.OrderedDict
-
-[cython]
-description = The Cython compiler for writing C extensions for the Python language.
-
-[cytoolz]
-description = Cython implementation of Toolz: High performance functional utilities
-
-[dash]
-description = A Python framework for building reactive web-apps. Developed by Plotly.
-
-[dash-core-components]
-description = Core component suite for Dash
-
-[dash-html-components]
-description = Vanilla HTML components for Dash
-
-[dash-renderer]
-description = Front-end component renderer for Dash
-
-[dash-table]
-description = Dash table
-
-[dask]
-description = Parallel PyData with Task Scheduling
-
-[dask-labextension]
-description = A Jupyter Notebook server extension manages Dask clusters.
-
-[dask-ml]
-description = A library for distributed and parallel machine learning
-
-[dask-searchcv]
-description = Tools for doing hyperparameter search with Scikit-Learn and Dask
-
-[databases]
-description = Async database support for Python.
-
-[dataclasses]
-description = A backport of the dataclasses module for Python 3.6
-
-[datafabric]
-description = Distributed In-Memory system for analytics
-
-[datasette]
-description = A tool for exploring and publishing data
-
-[datashader]
-description = Data visualization toolchain based on aggregating into a grid
-
-[datashape]
-description = A data description language.
-
-[db-py]
-description = a db package that doesn't suck
-
-[decorator]
-description = Decorators for Humans
-
-[defusedxml]
-description = XML bomb protection for Python stdlib modules
-
-[deprecated]
-description = Python @deprecated decorator to deprecate old python classes, functions or methods.
-
-[descartes]
-description = Use geometric objects as matplotlib paths and patches
-
-[diff-match-patch]
-description = Repackaging of Google's Diff Match and Patch libraries. Offers robust algorithms to perform the operations required for synchronizing plain text.
-
-[dill]
-description = serialize all of python
-
-[discretize]
-description = Discretization tools for finite volume and inverse problems
-
-[distribute]
-description = distribute legacy wrapper
-
-[distributed]
-description = Distributed scheduler for Dask
-
-[dm-sonnet]
-description = Sonnet is a library for building neural networks in TensorFlow.
-
-[dnspython]
-description = DNS toolkit
-
-[docopt]
-description = Pythonic argument parser, that will make you smile
-
-[docrepr]
-description = docrepr renders Python docstrings in HTML
-
-[docutils]
-description = Docutils -- Python Documentation Utilities
-
-[dopamine]
-description = A library to use DopamineLabs machine learning API
-
-[dynd]
-description = Python exposure of DyND
-
-[egenix-mx-base]
-description = eGenix mx Base Distribution for Python - mxDateTime, mxTextTools, mxProxy, mxTools, mxBeeBase, mxStack, mxQueue, mxURL, mxUID
-
-[ecos]
-description = This is the Python package for ECOS: Embedded Cone Solver. See Github page for more information.
-
-[edward]
-description = A library for probabilistic modeling, inference, and criticism
-
-[emcee]
-description = The Python ensemble sampling toolkit for MCMC
-
-[enum34]
-description = Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4
-
-[enum-compat]
-description = enum/enum34 compatibility package
-
-[entrypoints]
-description = Discover and load entry points from installed packages.
-
-[envisage]
-description = Extensible application framework
-
-[ephem]
-description = Compute positions of the planets and stars
-
-[eradicate]
-description = Removes commented-out code.
-
-[falcon]
-description = An unladen web framework for building APIs and app backends.
-
-[fast-histogram]
-description = Fast simple 1D and 2D histograms
-
-[fastai]
-description = fastai makes deep learning with PyTorch faster, more accurate, and easier
-
-[fastapi]
-description = FastAPI framework, high performance, easy to learn, fast to code, ready for production
-
-[fastcache]
-description = C implementation of Python 3 functools.lru_cache
-
-[fasteners]
-description = A python package that provides useful locks.
-
-[fastparquet]
-description = Python support for Parquet file format
-
-[fastprogress]
-description = A nested progress with plotting options for fastai
-
-[fastrlock]
-description = Fast, re-entrant optimistic lock implemented in Cython
-
-[fastscript]
-description = A fast way to turn your python function into a script
-
-[fbprophet]
-description = Automatic Forecasting Procedure
-
-[feather-format]
-description = Simple wrapper library to the Apache Arrow-based Feather File Format
-
-[fenics]
-description = The FEniCS Project Python Metapackage
-
-[filelock]
-description = A platform independent file lock.
-
-[fiona]
-description = Fiona reads and writes spatial data files
-
-[flake8]
-description = the modular source code checker: pep8, pyflakes and co
-
-[flask]
-description = A simple framework for building complex web applications.
-
-[flaskerize]
-description = Python CLI build/dev tool for templated code generation and project modification. Think Angular schematics for Python.
-
-[flask-accepts]
-description = Easy, opinionated Flask input/output handling with Flask-restx and Marshmallow
-
-[flask-compress]
-description = Compress responses in your Flask app with gzip.
-
-[flask-cors]
-description = A Flask extension adding a decorator for CORS support
-
-[flask-restplus]
-description = Fully featured framework for fast, easy and documented API development with Flask
-
-[flask-restx]
-description = Fully featured framework for fast, easy and documented API development with Flask
-
-[flask-seasurf]
-description = An updated CSRF extension for Flask.
-
-[flexx]
-description = Write desktop and web apps in pure Python.
-
-[flit]
-description = A simple packaging tool for simple packages.
-
-[folium]
-description = Make beautiful maps with Leaflet.js & Python
-
-[fonttools]
-description = Tools to manipulate font files
-
-[formlayout]
-description = The most easy way to create Qt form dialogs and widgets with Python
-
-[fs]
-description = Python's filesystem abstraction layer
-
-[fsspec]
-description = File-system specification
-
-[fuel]
-description = Data pipeline framework for machine learning
-
-[funcsigs]
-description = Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+
-
-[functools32]
-description = Backport of the functools module from Python 3.2.3 for use on 2.7 and PyPy.
-
-[future]
-description = Clean single-source support for Python 3 and 2
-
-[futures]
-description = Backport of the concurrent.futures package from Python 3
-
-[fuzzywuzzy]
-description = Fuzzy string matching in python
-
-[gast]
-description = Python AST that abstracts the underlying Python version
-
-[gdal]
-description = GDAL: Geospatial Data Abstraction Library
-
-[gensim]
-description = Python framework for fast Vector Space Modelling
-
-[geoana]
-description = geoana
-
-[geopy]
-description = Python Geocoding Toolbox
-
-[geographiclib]
-description = The geodesic routines from GeographicLib
-
-[geopandas]
-description = Geographic pandas extensions
-
-[geoplot]
-description = High-level geospatial plotting for Python.
-
-[geoviews]
-description = GeoViews is a Python library that makes it easy to explore and visualize geographical, meteorological, and oceanographic datasets, such as those used in weather, climate, and remote sensing research.
-
-[ggplot]
-description = ggplot for python
-
-[ghost-py]
-description = Webkit based webclient.
-
-[gin-config]
-description = Gin-Config: A lightweight configuration library for Python
-
-[gitdb2]
-description = A mirror package for gitdb
-
-[gitpython]
-description = Python Git Library
-
-[gmpy2]
-description = GMP/MPIR, MPFR, and MPC interface to Python 2.6+ and 3.x
-
-[gnumath]
-description = Extensible array functions that operate on xnd containers.
-
-[google-auth]
-description = Google Authentication Library
-
-[google-auth-oauthlib]
-description = Google Authentication Library
-
-[google-api-python-client]
-description = Google API Client Library for Python
-
-[google-pasta]
-description = pasta is an AST-based Python refactoring library
-
-[gr]
-description = Python visualization framework
-
-[graphql-relay]
-description = Relay library for graphql-core-next
-
-[graphql-core]
-description = GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL.
-
-[graphviz]
-description = Simple Python interface for Graphviz
-
-[graphene]
-description = GraphQL Framework for Python
-
-[graphql-server-core]
-description = GraphQL Server tools for powering your server
-
-[greenlet]
-description = Lightweight in-process concurrent programming
-
-[gridmap]
-description = Easily map Python functions onto a cluster using a DRMAA-compatible grid engine like Sun Grid Engine (SGE).
-
-[grpcio]
-description = HTTP/2-based RPC framework
-
-[guidata]
-description = Automatic graphical user interfaces generation for easy dataset editing and display
-
-[guiqwt]
-description = guiqwt is a set of tools for curve and image plotting (extension to PythonQwt)
-
-[gym]
-description = The OpenAI Gym: A toolkit for developing and comparing your reinforcement learning agents.
-
-[hdfs]
-description = HdfsCLI: API and command line interface for HDFS.
-
-[heapdict]
-description = a heap with decrease-key and increase-key operations
-
-[helpdev]
-description = HelpDev - Extracts information about the Python environment easily.
-
-[hiplot]
-description = High dimensional Interactive Plotting tool
-
-[holidays]
-description = Generate and work with holidays in Python
-
-[holoviews]
-description = Stop plotting your data - annotate your data and let it visualize itself.
-
-[hpack]
-description = Pure-Python HPACK header compression
-
-[hvplot]
-description = A high-level plotting API for the PyData ecosystem built on HoloViews.
-
-[html5lib]
-description = HTML parser based on the WHATWG HTML specification
-
-[httplib2]
-description = A comprehensive HTTP client library.
-
-[humanfriendly]
-description = Human friendly output for text interfaces using Python
-
-[husl]
-description = Human-friendly HSL
-
-[hupper]
-description = Integrated process monitor for developing and reloading daemons.
-
-[hypercorn]
-description = A ASGI Server based on Hyper libraries and inspired by Gunicorn.
-
-[hyperframe]
-description = HTTP/2 framing layer for Python
-
-[hypothesis]
-description = A library for property-based testing
-
-[h11]
-description = A pure-Python, bring-your-own-I/O implementation of HTTP/1.1
-
-[h2]
-description = HTTP/2 State-Machine based protocol implementation
-
-[h5py]
-description = Read and write HDF5 files from Python
-
-[ibis-framework]
-description = Productivity-centric Python Big Data Framework
-
-[ipydatawidgets]
-description = A set of widgets to help facilitate reuse of large datasets across widgets
-
-[idlex]
-description = IDLE Extensions for Python
-
-[idna]
-description = Internationalized Domain Names in Applications (IDNA)
-
-[imageio]
-description = Library for reading and writing a wide range of image, video, scientific, and volumetric data formats.
-
-[imageio-ffmpeg]
-description = FFMPEG wrapper for Python
-
-[imbalanced-learn]
-description = Toolbox for imbalanced dataset in machine learning.
-
-[immutables]
-description = Immutable Collections
-
-[imagesize]
-description = Getting image size from png/jpeg/jpeg2000/gif file
-
-[importlib-metadata]
-description = Read metadata from Python packages
-
-[intake]
-description = Data load and catalog system
-
-[intervaltree]
-description = Editable interval tree data structure for Python 2 and 3
-
-[ipycanvas]
-description = Interactive widgets library exposing the browser's Canvas API
-
-[ipykernel]
-description = IPython Kernel for Jupyter
-
-[ipyleaflet]
-description = A Jupyter widget for dynamic Leaflet maps
-
-[ipympl]
-description = Matplotlib Jupyter Extension
-
-[ipyparallel]
-description = Interactive Parallel Computing with IPython
-
-[ipyscales]
-description = A widget library for scales
-
-[ipython]
-description = IPython: Productive Interactive Computing
-
-[ipython-genutils]
-description = Vestigial utilities from IPython
-
-[ipython-sql]
-description = RDBMS access via IPython
-
-[ipyvega]
-description = IPython/Jupy
-
-[ipyvolume]
-description = IPython widget for rendering 3d volumes
-
-[ipyvuetify]
-description = Jupyter widgets based on vuetify UI components
-
-[ipywebrtc]
-description = WebRTC for Jupyter notebook/lab
-
-[ipywidgets]
-description = IPython HTML widgets for Jupyter
-
-[isort]
-description = A Python utility / library to sort Python imports.
-
-[itsdangerous]
-description = Various helpers to pass data to untrusted environments and back.
-
-[janus]
-description = Mixed sync-async queue to interoperate between asyncio tasks and classic threads
-
-[jax]
-description = Differentiate, compile, and transform Numpy code.
-
-[jedi]
-description = An autocompletion tool for Python that can be used for text editors.
-
-[jinja2]
-description = A small but fast and easy to use stand-alone template engine written in pure python.
-
-[jmespath]
-description = JSON Matching Expressions
-
-[joblib]
-description = Lightweight pipelining: using Python functions as pipeline jobs.
-
-[jnius]
-description = Dynamic access to Java classes from Python
-
-[jplephem]
-description = Use a JPL ephemeris to predict planet positions.
-
-[jsonschema]
-description = An implementation of JSON Schema validation for Python
-
-[json5]
-description = A Python implementation of the JSON5 data format.
-
-[julia]
-description = Julia/Python bridge with IPython support.
-
-[jupyter]
-description = Jupyter metapackage. Install all the Jupyter components in one go.
-
-[jupyter-echarts-pypkg]
-description = Echarts pypi packages for jupyter and python
-
-[jupyterlab]
-description = The JupyterLab notebook server extension.
-
-[jupyterlab-launcher]
-description = Jupyter Launcher
-
-[jupyterlab-sql]
-description = JupyterLab plugin for visualizing SQL databases
-
-[jupyter-client]
-description = Jupyter protocol implementation and client libraries
-
-[jupyter-console]
-description = Jupyter terminal console
-
-[jupyter-core]
-description = Jupyter core package. A base package on which Jupyter projects rely.
-
-[jupyter-panel-proxy]
-description = Jupyter Server Proxy for Panel applications
-
-[jupyterlab-pygments]
-description = Pygments theme
-
-[jupyterlab-server]
-description = JupyterLab Server
-
-[jupyter-server]
-description = The Jupyter Server
-
-[jupyter-sphinx]
-description = Jupyter Sphinx Extensions
-
-[jupytext]
-description = Jupyter notebooks as Markdown documents, Julia, Python or R scripts
-
-[kapteyn]
-description = Kapteyn Package: Python modules for astronomical applications
-
-[keras]
-description = Deep Learning for humans
-
-[keras-applications]
-description = Reference implementations of popular deep learning models
-
-[keras-preprocessing]
-description = Easy data preprocessing and data augmentation for deep learning models
-
-[keras-vis]
-description = Neural Network visualization toolkit for keras
-
-[keras-tuner]
-description = Hypertuner for Keras
-
-[keyring]
-description = Store and access your passwords safely.
-
-[kivy]
-description = A software library for rapid development of hardware-accelerated multitouch applications.
-
-[kivy-garden]
-description = Garden tool for kivy flowers.
-
-[kiwisolver]
-description = A fast implementation of the Cassowary constraint solver
-
-[knack]
-description = A Command-Line Interface framework
-
-[knit]
-description = Python wrapper for YARN Applications
-
-[kombu]
-description = Messaging library for Python.
-
-[lasagne]
-description = A lightweight library to build and train neural networks in Theano
-
-[lazy-object-proxy]
-description = A fast and thorough lazy object proxy.
-
-[libpython]
-description = The MinGW import library for Python
-
-[lightfm]
-description = LightFM recommendation model
-
-[lightning-python]
-description = A Python client library for the Lightning data visualization server
-
-[llvmlite]
-description = lightweight wrapper around basic LLVM functionality
-
-[llvmpy]
-description = Python bindings for LLVM
-
-[lmfit]
-description = Least-Squares Minimization with Bounds and Constraints
-
-[lml]
-description = Load me later. A lazy plugin management system.
-
-[lock]
-description = module for enabling file locks
-
-[locket]
-description = File-based locks for Python for Linux and Windows
-
-[locket-py]
-description = File-based locks for Python for Linux and Windows
-
-[logilab-astng]
-description = rebuild a new abstract syntax tree from Python's ast
-
-[logilab-common]
-description = collection of low-level Python packages and modules used by Logilab projects
-
-[logutils]
-description = Logging utilities
-
-[loky]
-description = A robust implementation of concurrent.futures.ProcessPoolExecutor
-
-[lunardate]
-description = A Chinese Calendar Library in Pure Python
-
-[lxml]
-description = Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API.
-
-[lz4]
-description = LZ4 Bindings for Python
-
-[macholib]
-description = Mach-O header analysis and editing
-
-[mahotas]
-description = Mahotas: Computer Vision Library
-
-[mako]
-description = A super-fast templating language that borrows the best ideas from the existing templating languages.
-
-[mapclassify]
-description = Classification Schemes for Choropleth Maps.
-
-[markdown]
-description = Python implementation of Markdown.
-
-[markdown2]
-description = A fast and complete Python implementation of Markdown
-
-[markupsafe]
-description = Safely add untrusted strings to HTML/XML markup.
-
-[marshmallow]
-description = A lightweight library for converting complex datatypes to and from native Python datatypes.
-
-[matplotlib]
-description = Python plotting package
-
-[mayavi]
-description = 3D scientific data visualization library and application
-
-[mccabe]
-description = McCabe checker, plugin for flake8
-
-[mercantile]
-description = Web mercator XYZ tile utilities
-
-[mercurial]
-description = Fast scalable distributed SCM (revision control, version control) system
-
-[metakernel]
-description = Metakernel for Jupyter
-
-[mingwpy]
-description = the python friendly windows compiler toolchain
-
-[mistune]
-description = The fastest markdown parser in pure Python
-
-[mizani]
-description = Scales for Python
-
-[mlxtend]
-description = Machine Learning Library Extensions
-
-[mkl-service]
-description = Python bindings to some MKL service functions
-
-[mlflow]
-description = MLflow: An ML Workflow Tool
-
-[mock]
-description = Rolling backport of unittest.mock for all Pythons
-
-[modergnl]
-description = Modern OpenGL binding for python
-
-[modin]
-description = Modin: Make your pandas code run faster by changing one line of code.
-
-[monotonic]
-description = An implementation of time.monotonic() for Python 2 & < 3.3
-
-[more-itertools]
-description = More routines for operating on iterables, beyond itertools
-
-[moviepy]
-description = Video editing with Python
-
-[mpldatacursor]
-description = Interactive data cursors for Matplotlib
-
-[mpld3]
-description = D3 Viewer for Matplotlib
-
-[mpl-scatter-density]
-description = Matplotlib helpers to make density scatter plots
-
-[mpmath]
-description = Python library for arbitrary-precision floating-point arithmetic
-
-[msgpack]
-description = MessagePack (de)serializer.
-
-[msgpack-numpy]
-description = Numpy data serialization using msgpack
-
-[msgpack-python]
-description = MessagePack (de)serializer.
-
-[multidict]
-description = multidict implementation
-
-[multipledispatch]
-description = Multiple dispatch
-
-[multiprocess]
-description = better multiprocessing and multithreading in python
-
-[murmurhash]
-description = Cython bindings for MurmurHash
-
-[munch]
-description = A dot-accessible dictionary (a la JavaScript objects)
-
-[mxbase]
-description = eGenix.com mx Base Distribution: mxDateTime, mxTextTools, mxProxy, mxBeeBase, mxURL, mxUID, mxStack, mxQueue and mxTools
-
-[mypy]
-description = Optional static typing for Python
-
-[mypy-extensions]
-description = Experimental type system extensions for programs checked with the mypy typechecker.
-
-[mysql-connector-python]
-description = MySQL driver written in Python
-
-[nbbrowserpdf]
-description = LaTeX-free PDF generation from Jupyter Notebooks
-
-[nbclient]
-description = A client library for executing notebooks. Formally nbconvert's ExecutePreprocessor.
-
-[nbconvert]
-description = Converting Jupyter Notebooks
-
-[nbconvert-reportlab]
-description = Convert notebooks to PDF using Reportlab
-
-[nbdev]
-description = Writing a library entirely in notebooks
-
-[nbdime]
-description = Diff and merge of Jupyter Notebooks
-
-[nbformat]
-description = The Jupyter Notebook format
-
-[nbgrader]
-description = A system for assigning and grading notebooks
-
-[nbpresent]
-description = Next generation slides from Jupyter Notebooks
-
-[nbsphinx]
-description = Jupyter Notebook Tools for Sphinx
-
-[ndtypes]
-description = Dynamic types for data description and in-memory computations.
-
-[netcdftime]
-description = Time-handling functionality from netcdf4-python
-
-[nest-asyncio]
-description = Patch asyncio to allow nested event loops
-
-[netcdf4]
-description = Provides an object-oriented python interface to the netCDF version 4 library.
-
-[networkx]
-description = Python package for creating and manipulating graphs and networks
-
-[nltk]
-description = Natural Language Toolkit
-
-[nose]
-description = nose extends unittest to make testing easier
-
-[notebook]
-description = A web-based notebook environment for interactive computing
-
-[nteract-on-jupyter]
-description = Extension for the jupyter notebook server and nteract
-
-[numba]
-description = compiling Python code using LLVM
-
-[numcodecs]
-description = A Python package providing buffer compression and transformation codecs for use in data storage and communication applications.
-
-[numdifftools]
-description = Solves automatic numerical differentiation problems in one or more variables.
-
-[numexpr]
-description = Fast numerical expression evaluator for NumPy
-
-[numpy]
-description = NumPy is the fundamental package for array computing with Python.
-
-[numpydoc]
-description = Sphinx extension to support docstrings in Numpy format
-
-[nvidia-ml-py3]
-description = Python Bindings for the NVIDIA Management Library
-
-[oauthlib]
-description = A generic, spec-compliant, thorough implementation of the OAuth request-signing logic
-
-[oauth2client]
-description = OAuth 2.0 client library
-
-[observations]
-description = Tools for loading standard data sets in machine learning
-
-[octave-kernel]
-description = A Jupyter kernel for Octave.
-
-[oct2py]
-description = Python to GNU Octave bridge --> run m-files from python.
-
-[odo]
-description = Data migration utilities
-
-[olefile]
-description = Python package to parse, read and write Microsoft OLE2 files (Structured Storage or Compound Document, Microsoft Office)
-
-[opencv-python]
-description = Wrapper package for OpenCV python bindings.
-
-[openimageio]
-description = a library for reading and writing images with emphasis on animation and visual effects.
-
-[openpyxl]
-description = A Python library to read/write Excel 2010 xlsx/xlsm files
-
-[opt-einsum]
-description = Optimizing numpys einsum function
-
-[orange]
-description = Orange, a component-based data mining framework.
-
-[osqp]
-description = OSQP: The Operator Splitting QP Solver
-
-[outcome]
-description = Capture the outcome of Python function calls.
-
-[packaging]
-description = Core utilities for Python packages
-
-[palettable]
-description = Color palettes for Python
-
-[palladium]
-description = Framework for setting up predictive analytics services
-
-[pandas]
-description = Powerful data structures for data analysis, time series, and statistics
-
-[pandasql]
-description = sqldf for pandas
-
-[pandas-datareader]
-description = Data readers extracted from the pandas codebase,should be compatible with recent pandas versions
-
-[pandas-ply]
-description = functional data manipulation for pandas
-
-[pandocfilters]
-description = Utilities for writing pandoc filters in python
-
-[panel]
-description = A high level app and dashboarding solution for Python.
-
-[papermill]
-description = Parametrize and run Jupyter and nteract Notebooks
-
-[param]
-description = Declarative Python programming using Parameters.
-
-[parambokeh]
-description = ParamBokeh provides an easy way to generate a UI for param based classes in the notebook or on bokeh server.
-
-[paramnb]
-description = Generate ipywidgets from Parameterized objects in the notebook
-
-[paramiko]
-description = SSH2 protocol library
-
-[parse]
-description = parse() is the opposite of format()
-
-[parso]
-description = A Python Parser
-
-[partd]
-description = Appendable key-value storage
-
-[passlib]
-description = comprehensive password hashing framework supporting over 30 schemes
-
-[pathspec]
-description = Utility library for gitignore style pattern matching of file paths.
-
-[pathtools]
-description = File system general utilities
-
-[path-py]
-description = A module wrapper for os.path
-
-[patsy]
-description = A Python package for describing statistical models and for building design matrices.
-
-[pbr]
-description = Python Build Reasonableness
-
-[pdfrw]
-description = PDF file reader/writer library
-
-[pdvega]
-description = Pandas plotting interface to Vega and Vega-Lite
-
-[peewee]
-description = a little orm
-
-[pefile]
-description = Python PE parsing module
-
-[pep8]
-description = Python style guide checker
-
-[perf]
-description = Python module to generate and modify perf
-
-[performance]
-description = Python benchmark suite
-
-[pexpect]
-description = Pexpect allows easy control of interactive console applications.
-
-[pgmagick]
-description = Yet Another Python wrapper for GraphicsMagick
-
-[pg8000]
-description = PostgreSQL interface library
-
-[pkginfo]
-description = Query metadatdata from sdists / bdists / installed packages.
-
-[picklable-itertools]
-description = itertools. But picklable. Even on Python 2.
-
-[pickleshare]
-description = Tiny 'shelve'-like database with concurrency support
-
-[pil]
-description = Python Imaging Library
-
-[pillow]
-description = Python Imaging Library (Fork)
-
-[pint]
-description = Physical quantities module
-
-[pip]
-description = The PyPA recommended tool for installing Python packages.
-
-[plotly]
-description = An open-source, interactive graphing library for Python
-
-[plotnine]
-description = A grammar of graphics for python
-
-[plotpy]
-description = Plotpy is a library which results from merge of guidata and guiqwt.
-
-[pluggy]
-description = plugin and hook calling mechanisms for python
-
-[ply]
-description = Python Lex & Yacc
-
-[polygon2]
-description = Polygon2 is a Python-2 package that handles polygonal shapes in 2D
-
-[polygon3]
-description = Polygon3 is a Python-3 package that handles polygonal shapes in 2D
-
-[pomegranate]
-description = Pomegranate is a graphical models library for Python, implemented in Cython for speed.
-
-[portalocker]
-description = Wraps the portalocker recipe for easy usage
-
-[portpicker]
-description = A library to choose unique available network ports.
-
-[poyo]
-description = A lightweight YAML Parser for Python. 🐓
-
-[ppci]
-description = A compiler for ARM, X86, MSP430, xtensa and more implemented in pure Python
-
-[preshed]
-description = Cython hash table that trusts the keys are pre-hashed
-
-[prettytable]
-description = A simple Python library for easily displaying tabular data in a visually appealing ASCII table format.
-
-[prettytensor]
-description = Pretty Tensor makes learning beautiful
-
-[priority]
-description = A pure-Python implementation of the HTTP/2 priority tree
-
-[proglog]
-description = Log and progress bar manager for console, notebooks, web...
-
-[progressbar]
-description = Text progress bar library for Python.
-
-[progressbar2]
-description = A Python Progressbar library to provide visual (yet text based) progress to long running operations.
-
-[prometheus-client]
-description = Python client for the Prometheus monitoring system.
-
-[promise]
-description = Promises/A+ implementation for Python
-
-[properties]
-description = properties: an organizational aid and wrapper for validation and tab completion of class properties
-
-[prompt-toolkit]
-description = Library for building powerful interactive command lines in Python
-
-[prospector]
-description = Prospector: python static analysis tool
-
-[protobuf]
-description = Protocol Buffers
-
-[pscript]
-description = Python to JavaScript compiler.
-
-[psutil]
-description = Cross-platform lib for process and system monitoring in Python.
-
-[psycopg2]
-description = psycopg2 - Python-PostgreSQL Database Adapter
-
-[ptpython]
-description = Python REPL build on top of prompt_toolkit
-
-[ptvsd]
-description = Remote debugging server for Python support in Visual Studio and Visual Studio Code
-
-[ptyprocess]
-description = Run a subprocess in a pseudo terminal
-
-[pulp]
-description = PuLP is an LP modeler written in python. PuLP can generate MPS or LP files and call GLPK, COIN CLP/CBC, CPLEX, and GUROBI to solve linear problems.
-
-[pweave]
-description = Scientific reports with embedded python computations with reST, LaTeX or markdown
-
-[py]
-description = library with cross-python path, ini-parsing, io, code, log facilities
-
-[pyaml]
-description = PyYAML-based module to produce pretty and readable YAML-serialized data
-
-[pyct]
-description = python package common tasks for users (e.g. copy examples, fetch data, ...)
-
-[pyarrow]
-description = Python library for Apache Arrow
-
-[pyasn1]
-description = ASN.1 types and codecs
-
-[pyasn1-modules]
-description = A collection of ASN.1-based protocols modules.
-
-[pyaudio]
-description = Bindings for PortAudio v19, the cross-platform audio input/output stream library.
-
-[pybars3]
-description = Handlebars.js templating for Python 3 and 2
-
-[pybind11]
-description = Seamless operability between C++11 and Python
-
-[pycares]
-description = Python interface for c-ares
-
-[pycairo]
-description = Python interface for cairo
-
-[pycodestyle]
-description = Python style guide checker
-
-[pycosat]
-description = bindings to picosat (a SAT solver)
-
-[pycparser]
-description = C parser in Python
-
-[pydantic]
-description = Data validation and settings management using python 3.6 type hinting
-
-[pydeck]
-description = Widget for deck.gl maps
-
-[pydicom]
-description = Pure python package for DICOM medical file reading and writing
-
-[pydispatcher]
-description = Multi-producer-multi-consumer signal dispatching mechanism
-
-[pydocstyle]
-description = Python docstring style checker
-
-[pydot-ng]
-description = Python interface to Graphviz's Dot
-
-[pyecharts]
-description = Python options, make charting easier
-
-[pyecharts-javascripthon]
-description = Embeded Python functions in pyecharts
-
-[pyecharts-jupyter-installer]
-description = Install pyecharts extensions into jupyter
-
-[pyeda]
-description = Python Electronic Design Automation
-
-[pyepsg]
-description = Easy access to the EPSG database via http epsg.io/
-
-[pyface]
-description = traits-capable windowing framework
-
-[pyflakes]
-description = passive checker of Python programs
-
-[pyflux]
-description = PyFlux: A time-series analysis library for Python
-
-[pygame]
-description = Python Game Development
-
-[pygbm]
-description = Experimental, numba-based Gradient Boosting Machines
-
-[pygit2]
-description = Python bindings for libgit2.
-
-[pyglet]
-description = Cross-platform windowing and multimedia library
-
-[pygments]
-description = Pygments is a syntax highlighting package written in Python.
-
-[pygraphviz]
-description = Python interface to Graphviz
-
-[pyhdf]
-description = pyhdf: Python interface to the NCSA HDF4 library.
-
-[pyhive]
-description = Python interface to Hive
-
-[pyinstaller]
-description = PyInstaller bundles a Python application and all its dependencies into a single package.
-
-[pylama]
-description = pylama -- Code audit tool for python
-
-[pylearn2]
-description = A Machine Learning library based on Theano
-
-[pylint]
-description = python code static checker
-
-[pylons]
-description = Pylons Web Framework
-
-[pymatsolver]
-description = pymatsolver: Matrix Solvers for Python
-
-[pymc]
-description = Markov Chain Monte Carlo sampling toolkit.
-
-[pymc3]
-description = Probabilistic Programming in Python: Bayesian Modeling and Probabilistic Machine Learning with Theano
-
-[pymeta3]
-description = Pattern-matching language based on OMeta for Python 3 and 2
-
-[pymkl]
-description = Python wrapper of Intel MKL routines
-
-[pymongo]
-description = Python driver for MongoDB
-
-[pympler]
-description = A development tool to measure, monitor and analyze the memory behavior of Python objects.
-
-[pynacl]
-description = Python binding to the Networking and Cryptography (NaCl) library
-
-[pyodbc]
-description = DB API Module for ODBC
-
-[pyomo]
-description = Pyomo: Python Optimization Modeling Objects
-
-[pyopencl]
-description = Python wrapper for OpenCL
-
-[pyopengl]
-description = Standard OpenGL bindings for Python
-
-[pyopenssl]
-description = Python wrapper module around the OpenSSL library
-
-[pypandoc]
-description = Thin wrapper for pandoc.
-
-[pypdf2]
-description = PDF toolkit
-
-[pyparsing]
-description = Python parsing module
-
-[pyperf]
-description = Python module to run and analyze benchmarks
-
-[pyproj]
-description = Python interface to PROJ (cartographic projections and coordinate transformations library)
-
-[pypiwin32]
-description = Python for Windows Extensions
-
-[pyqt]
-description = Cross-platform Application Framework: GUI, widgets, SQL, OpenGL, XML, Unicode...
-
-[pyqtchart]
-description = Python bindings for the Qt Charts library
-
-[pyqtdatavisualization]
-description = Python bindings for the Qt Data Visualization library
-
-[pyqtdeploy]
-description = PyQt Application Deployment Tool
-
-[pyqtgraph]
-description = Scientific Graphics and GUI Library for Python
-
-[pyqtpurchasing]
-description = Python bindings for the Qt Purchasing library
-
-[pyqt4]
-description = Python bindings for the Qt cross platform GUI toolkit
-
-[pyqt5]
-description = Python bindings for the Qt cross platform application toolkit
-
-[pyqt5-sip]
-description = The sip module support for PyQt5
-
-[pyqtdoc]
-description = PyQtdoc installs Qt documentation for PyQt
-
-[pyqtdesignerplugins]
-description = PyQtdesignerplugins installs Qt Designer plugins for PyQt4
-
-[pyqtwebengine]
-description = Python bindings for the Qt WebEngine framework
-
-[pyqwt]
-description = 2D plotting library (set of Python bindings for the Qwt library featuring fast plotting)
-
-[pyramid]
-description = The Pyramid Web Framework, a Pylons project
-
-[pyreadline]
-description = A python implmementation of GNU readline.
-
-[pyroma]
-description = Test your project's packaging friendliness
-
-[pyrro-ppl]
-description = A Python library for probabilistic modeling and inference
-
-[pyrsistent]
-description = Persistent/Functional/Immutable data structures
-
-[pysal]
-description = A library of spatial analysis functions.
-
-[pyserial]
-description = Python Serial Port Extension
-
-[pyshp]
-description = Pure Python read/write support for ESRI Shapefile format
-
-[pyside]
-description = Python bindings for the Qt cross-platform application and UI framework
-
-[pyside2]
-description = Python bindings for the Qt cross-platform application and UI framework
-
-[pyspark]
-description = Apache Spark Python API
-
-[pystache]
-description = Mustache for Python
-
-[pystan]
-description = Python interface to Stan, a package for Bayesian inference
-
-[pytest]
-description = pytest: simple powerful testing with Python
-
-[pytest-runner]
-description = Invoke py.test as distutils command with dependency resolution
-
-[python-crfsuite]
-description = Python binding for CRFsuite
-
-[python-dateutil]
-description = Extensions to the standard Python datetime module
-
-[python-hdf4]
-description = Python-HDF4: Python interface to the NCSA HDF4 library.
-
-[python-igraph]
-description = High performance graph data structures and algorithms
-
-[python-mimeparse]
-description = A module provides basic functions for parsing mime-type names and matching them against a list of media-ranges.
-
-[python-qwt]
-description = Qt plotting widgets for Python
-
-[python-jsonrpc-server]
-description = JSON RPC 2.0 server library
-
-[python-language-server]
-description = Python Language Server for the Language Server Protocol
-
-[python-levenshtein]
-description = Python extension for computing string edit distances and similarities.
-
-[python-multipart]
-description = A streaming multipart parser for Python
-
-[python-snappy]
-description = Python library for the snappy compression library from Google
-
-[pythonnet]
-description = .Net and Mono integration for Python
-
-[pythonqwt]
-description = Qt plotting widgets for Python
-
-[python-twitter]
-description = A Python wrapper around the Twitter API
-
-[python-zstandard]
-description = Python bindings to the Zstandard (zstd) compression library
-
-[pythran]
-description = Ahead of Time compiler for numeric kernels
-
-[pythreejs]
-description = Interactive 3d graphics for the Jupyter notebook, using Three.js from Jupyter interactive widgets.
-
-[pytools]
-description = A collection of tools for Python
-
-[pytorch-transformers]
-description = Repository of pre-trained NLP Transformer models: BERT & RoBERTa, GPT & GPT-2, Transformer-XL, XLNet and XLM
-
-[pytz]
-description = World timezone definitions, modern and historical
-
-[pytzdata]
-description = The Olson timezone database for Python.
-
-[pyutilib]
-description = PyUtilib: A collection of Python utilities
-
-[pyvisa]
-description = Python VISA bindings for GPIB, RS232, TCPIP and USB instruments
-
-[pyviz]
-description = How to solve visualization problems with Python tools.
-
-[pyviz-comms]
-description = Bidirectional communication for the PyViz ecosystem.
-
-[pywavelets]
-description = PyWavelets, wavelet transform module
-
-[pywin32]
-description = Python for Window Extensions
-
-[pywin32-ctypes]
-description = A (partial) reimplementation of pywin32 that is pure python (uses ctypes/cffi)
-
-[pywinpty]
-description = Python bindings for the winpty library
-
-[pywinusb]
-description = A package that simplifies USB/HID communications on windows
-
-[pyyaml]
-description = YAML parser and emitter for Python
-
-[pyzmq]
-description = Python bindings for 0MQ
-
-[pyzo]
-description = the Python IDE for scientific computing
-
-[py-spy]
-description = A Sampling Profiler for Python
-
-[qdarkstyle]
-description = The most complete dark stylesheet for Python and Qt applications
-
-[qtawesome]
-description = FontAwesome icons in PyQt and PySide applications
-
-[qtconsole]
-description = Jupyter Qt console
-
-[qtpy]
-description = Provides an abstraction layer on top of the various Qt bindings (PyQt5, PyQt4 and PySide) and additional custom QWidgets.
-
-[qscintilla]
-description = Python bindings for the QScintilla programmers editor widget
-
-[quantecon]
-description = QuantEcon is a package to support all forms of quantitative economic modelling.
-
-[quart]
-description = A Python ASGI web microframework with the same API as Flask
-
-[quiver-engine]
-description = Interactive per-layer visualization for convents in keras
-
-[radon]
-description = Code Metrics in Python
-
-[rasterio]
-description = Fast and direct raster I/O for use with Numpy and SciPy
-
-[ray]
-description = A system for parallel and distributed Python that unifies the ML ecosystem.
-
-[readme-renderer]
-description = readme_renderer is a library for rendering "readme" descriptions for Warehouse
-
-[recommonmark]
-description = A docutils-compatibility bridge to CommonMark, enabling you to write CommonMark inside of Docutils & Sphinx projects.
-
-[redis]
-description = Python client for Redis key-value store
-
-[regex]
-description = Alternative regular expression module, to replace re.
-
-[reportlab]
-description = The Reportlab Toolkit
-
-[requests]
-description = Python HTTP for Humans.
-
-[requests-file]
-description = File transport adapter for Requests
-
-[requests-ftp]
-description = FTP Transport Adapter for Requests.
-
-[requests-threads]
-description = A Requests session that returns awaitable Twisted Deferreds instead of response objects.
-
-[requests-toolbelt]
-description = A utility belt for advanced users of python-requests
-
-[requests-oauthlib]
-description = OAuthlib authentication support for Requests.
-
-[responder]
-description = A sorta familiar HTTP framework.
-
-[retrying]
-description = Retrying
-
-[rfc3986]
-description = Validating URI References per RFC 3986
-
-[rise]
-description = Reveal.js - Jupyter/IPython Slideshow Extension
-
-[rodeo]
-description = an ide for data analysis in python
-
-[rope]
-description = a python refactoring library...
-
-[rope-py3k]
-description = a python refactoring library...
-
-[rpy2]
-description = Python interface to the R language (embedded R)
-
-[rsa]
-description = Pure-Python RSA implementation
-
-[rst2pdf]
-description = Convert reStructured Text to PDF via ReportLab.
-
-[rtree]
-description = R-Tree spatial index for Python GIS
-
-[ruamel-yaml]
-description = a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order
-
-[ruamel-yaml-clib]
-description = C version of reader, parser and emitter for ruamel.yaml derived from libyaml
-
-[runipy]
-description = Run IPython notebooks from the command line
-
-[rx]
-description = Reactive Extensions (Rx) for Python
-
-[s3fs]
-description = Convenient Filesystem interface over S3
-
-[s3transfer]
-description = An Amazon S3 Transfer Manager
-
-[sasl]
-description = Cyrus-SASL bindings for Python
-
-[schemapi]
-description = schemapi: generate Python APIs from JSONSchema specifications
-
-[scidoc]
-description = Scidoc installs scientific Python libraries documentation
-
-[scikits-audiolab]
-description = Audio file I/O using NumPy arrays
-
-[scikits-timeseries]
-description = Time series manipulation
-
-[scikit-fuzzy]
-description = Fuzzy logic toolkit for SciPy
-
-[scikit-garden]
-description = A garden of scikit-learn compatible trees
-
-[scikit-learn]
-description = A set of python modules for machine learning and data mining
-category = scientific
-
-[scikit-image]
-description = Image processing routines for SciPy
-category = improc
-
-[scikit-neuralnetwork]
-description = Deep neural networks without the learning cliff! A wrapper library compatible with scikit-learn.
-
-[scikit-optimize]
-description = Sequential model-based optimization toolbox.
-
-[scilab2py]
-description = Python to Scilab bridge
-
-[scilab-kernel]
-description = A Jupyter kernel for Scilab.
-
-[scipy]
-description = SciPy: Scientific Library for Python
-
-[scrapy]
-description = A high-level Python Screen Scraping framework
-
-[scs]
-description = scs: splitting conic solver
-
-[seaborn]
-description = seaborn: statistical data visualization
-
-[semantic-version]
-description = A library implementing the 'SemVer' scheme.
-
-[send2trash]
-description = Send file to trash natively under Mac OS X, Windows and Linux.
-
-[service-identity]
-description = Service identity verification for pyOpenSSL.
-
-[setuptools]
-description = Easily download, build, install, upgrade, and uninstall Python packages
-
-[setuptools-git]
-description = Setuptools revision control system plugin for Git
-
-[sframe]
-description = SFrame is an scalable, out-of-core dataframe, which allows you to work with datasets that are larger than the amount of RAM on your system.
-
-[sgp4]
-description = Track earth satellite TLE orbits using up-to-date 2010 version of SGP4
-
-[shap]
-description = A unified approach to explain the output of any machine learning model.
-
-[shapely]
-description = Geometric objects, predicates, and operations
-
-[shiboken2]
-description = Python / C++ bindings helper module
-
-[simpervisor]
-description = Simple async process supervisor
-
-[simplegeneric]
-description = Simple generic functions (similar to Python's own len(), pickle.dump(), etc.)
-
-[simplejson]
-description = Simple, fast, extensible JSON encoder/decoder for Python
-
-[simpy]
-description = Event discrete, process based simulation for Python.
-
-[singledispatch]
-description = This library brings functools.singledispatch from Python 3.4 to Python 2.6-3.3.
-
-[sip]
-description = A Python bindings generator for C/C++ libraries
-
-[six]
-description = Python 2 and 3 compatibility utilities
-
-[sklearn-theano]
-description = Scikit-learn compatible tools using theano
-
-[skll]
-description = SciKit-Learn Laboratory makes it easier to run machine learning experiments with scikit-learn.
-
-[skorch]
-description = scikit-learn compatible neural network library for pytorch
-
-[skyfield]
-description = Elegant astronomy for Python
-
-[smmap]
-description = A pure Python implementation of a sliding window memory map manager
-
-[smmap2]
-description = A mirror package for smmap
-
-[snakeviz]
-description = A web-based viewer for Python profiler output
-
-[sniffio]
-description = Sniff out which async library your code is running under
-
-[snowballstemmer]
-description = This package provides 26 stemmers for 25 languages generated from Snowball algorithms.
-
-[snuggs]
-description = Snuggs are s-expressions for Numpy
-
-[sortedcollections]
-description = Python Sorted Collections
-
-[sortedcontainers]
-description = Sorted Containers -- Sorted List, Sorted Dict, Sorted Set
-
-[sounddevice]
-description = Play and Record Sound with Python
-
-[soupsieve]
-description = A modern CSS selector implementation for Beautiful Soup.
-
-[spacy]
-description = Industrial-strength Natural Language Processing (NLP) in Python
-
-[sparse]
-description = Sparse n-dimensional arrays
-
-[sphinx]
-description = Tool for generating documentation which uses reStructuredText as its markup language
-
-[sphinxcontrib-applehelp]
-description = sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books
-
-[sphinxcontrib-devhelp]
-description = sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document.
-
-[sphinxcontrib-htmlhelp]
-description = sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files
-
-[sphinxcontrib-jsmath]
-description = A sphinx extension which renders display math in HTML via JavaScript
-
-[sphinxcontrib-qthelp]
-description = sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document.
-
-[sphinxcontrib-websupport]
-description = Sphinx API for Web Apps
-
-[sphinxcontrib-serializinghtml]
-description = sphinxcontrib-serializinghtml is a sphinx extension which outputs "serialized" HTML files (json and pickle).
-
-[sphinx-rtd-theme]
-description = Read the Docs theme for Sphinx
-
-[spyder]
-description = The Scientific Python Development Environment
-
-[spyder-kernels]
-description = Jupyter kernels for Spyder's console
-
-[spyder-notebook]
-description = Jupyter notebook integration with Spyder
-
-[spyder-reports]
-description = Spyder-IDE plugin for Markdown reports using Pweave.
-
-[spyder-terminal]
-description = Spyder Plugin for displaying a virtual terminal (OS independent) inside the main Spyder window
-
-[spyder-line-profiler]
-description = Plugin for the Spyder IDE that integrates the Python line profiler.
-
-[spyder-memory-profiler]
-description = Plugin for the Spyder IDE that integrates the Python memory profiler
-
-[spyder-autopep8]
-description = A plugin to run the autopep8 python linter from within the spyder editor
-
-[sqlalchemy]
-description = Database Abstraction Library
-
-[sqlite-bro]
-description = a graphic SQLite Client in 1 Python file
-
-[sqlite-web]
-description = Web-based SQLite database browser.
-
-[sqlparse]
-description = Non-validating SQL parser
-
-[starlette]
-description = The little ASGI library that shines.
-
-[statsmodels]
-description = Statistical computations and models for Python
-
-[stormhttp]
-description = Lightning-fast asynchronous web framework for Python 3.5+
-
-[streamlite]
-description = Frontend library for machine learning engineers
-
-[streamz]
-description = Streams
-
-[supersmoother]
-description = Python implementation of Friedman's Supersmoother
-
-[swifter]
-description = A package which efficiently applies any function to a pandas dataframe or series in the fastest available manner
-
-[sympy]
-description = Computer algebra system (CAS) in Python
-
-[tables]
-description = Hierarchical datasets for Python
-
-[tabulate]
-description = Pretty-print tabular data
-
-[tblib]
-description = Traceback serialization library.
-
-[tb-nightly]
-description = TensorBoard lets you watch Tensors Flow
-
-[tenacity]
-description = Retry code until it succeeds
-
-[tensorboard]
-description = TensorBoard lets you watch Tensors Flow
-
-[tensorflow]
-description = TensorFlow is an open source machine learning framework for everyone.
-
-[tensorflow-cpu]
-description = TensorFlow is an open source machine learning framework for everyone.
-
-[tensorflow-estimator]
-description = TensorFlow Estimator.
-
-[tensorflow-plugin-wit]
-description = What-If Tool TensorBoard plugin.
-
-[tensorflow-probability]
-description = Probabilistic modeling and statistical inference in TensorFlow
-
-[tensorflow-tensorboard]
-description = TensorBoard lets you watch Tensors Flow
-
-[termcolor]
-description = ANSII Color formatting for output in terminal.
-
-[terminado]
-description = Terminals served to xterm.js using Tornado websockets
-
-[terminaltables]
-description = Generate simple tables in terminals from a nested list of strings.
-
-[testfixtures]
-description = A collection of helpers and mock objects for unit tests and doc tests.
-
-[testpath]
-description = Test utilities for code working with files and commands
-
-[textwrap3]
-description = textwrap from Python 3.6 backport (plus a few tweaks)
-
-[tf-estimator-nightly]
-description = TensorFlow Estimator.
-
-[thinc]
-description = Practical Machine Learning for NLP
-
-[theano]
-description = Optimizing compiler for evaluating mathematical expressions on CPUs and GPUs.
-
-[thrift]
-description = Python bindings for the Apache Thrift RPC system
-
-[thriftpy]
-description = Pure python implementation of Apache Thrift.
-
-[thrift-sasl]
-description = Thrift SASL Python module that implements SASL transports for Thrift (`TSaslClientTransport`).
-
-[toml]
-description = Python Library for Tom's Obvious, Minimal Language
-
-[toolz]
-description = List processing tools and functional utilities
-
-[torch]
-description = Tensors and Dynamic neural networks in Python with strong GPU acceleration
-
-[torchfile]
-description = Torch7 binary serialized file parser
-
-[torchvision]
-description = image and video datasets and models for torch deep learning
-
-[tornado]
-description = Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed.
-
-[tpot]
-description = Tree-based Pipeline Optimization Tool
-
-[tqdm]
-description = Fast, Extensible Progress Meter
-
-[traitlets]
-description = Traitlets Python config system
-
-[traits]
-description = Explicitly typed attributes for Python
-
-[traitsui]
-description = traitsui: traits-capable user interfaces
-
-[traittypes]
-description = Scipy trait types
-
-[tranquilizer]
-description = Put your functions to REST
-
-[trio]
-description = A friendly Python library for async concurrency and I/O
-
-[trio-asyncio]
-description = A re-implementation of the asyncio mainloop on top of Trio
-
-[ttfquery]
-description = FontTools-based package for querying system fonts
-
-[tweepy]
-description = Twitter library for python
-
-[twine]
-description = Collection of utilities for publishing packages on PyPI
-
-[twisted]
-description = An asynchronous networking framework written in Python
-
-[twitter]
-description = An API and command-line toolset for Twitter (twitter.com)
-
-[twython]
-description = Actively maintained, pure Python wrapper for the Twitter API. Supports both normal and streaming Twitter APIs
-
-[typed-ast]
-description = a fork of Python 2 and 3 ast modules with type comment support
-
-[typing]
-description = Type Hints for Python
-
-[typing-extensions]
-description = Backported and Experimental Type Hints for Python 3.5+
-
-[tzlocal]
-description = tzinfo object for the local timezone
-
-[uarray]
-description = Array interface object for Python with pluggable backends and a multiple-dispatchmechanism for defining down-stream functions
-
-[uncertainties]
-description = Transparent calculations with uncertainties on the quantities involved (aka error propagation); fast calculation of derivatives
-
-[uritemplate]
-description = URI templates
-
-[urllib3]
-description = HTTP library with thread-safe connection pooling, file post, and more.
-
-[usjon]
-description = Ultra fast JSON encoder and decoder for Python
-
-[uvicorn]
-description = The lightning-fast ASGI server.
-
-[uvloop]
-description = Fast implementation of asyncio event loop on top of libuv
-
-[validators]
-description = Python Data Validation for Humans™.
-
-[vectormath]
-description = vectormath: vector math utilities for Python
-
-[vega]
-description = A Jupyter widget for Vega 5 and Vega-Lite 4
-
-[vega-datasets]
-description = A Python package for offline access to Vega datasets
-
-[vega3]
-description = Deprecated: please use vega
-
-[verboselogs]
-description = Verbose logging level for Python's logging module
-
-[vispy]
-description = Interactive visualization in Python
-
-[visdom]
-description = A tool for visualizing live, rich data for Torch and Numpy
-
-[vitables]
-description = A viewer for PyTables package
-
-[voila]
-description = Serving read-only live Jupyter notebooks
-
-[voila-vuetify]
-description = A vuetify template for Voila
-
-[vpython]
-description = VPython for Jupyter Notebook
-
-[vtk]
-description = VTK is an open-source toolkit for 3D computer graphics, image processing, and visualization
-
-[watchdog]
-description = Filesystem events monitoring
-
-[wcwidth]
-description = Measures number of Terminal column cells of wide-character codes
-
-[webencodings]
-description = Character encoding aliases for legacy web content
-
-[websockets]
-description = An implementation of the WebSocket Protocol (RFC 6455 & 7692)
-
-[werkzeug]
-description = The comprehensive WSGI web application library.
-
-[wheel]
-description = A built-package format for Python
-
-[wheelhouse-uploader]
-description = Upload wheels to any cloud storage supported by Libcloud
-
-[whitenoise]
-description = Radically simplified static file serving for WSGI applications
-
-[whichcraft]
-description = This package provides cross-platform cross-python shutil.which functionality.
-
-[whoosh]
-description = Fast, pure-Python full text indexing, search, and spell checking library.
-
-[widgetsnbextension]
-description = IPython HTML widgets for Jupyter
-
-[winpython]
-description = WinPython distribution tools, including WPPM
-url = http://winpython.github.io/
-
-[winrt]
-description = Access Windows Runtime APIs from Python
-
-[win-unicode-console]
-description = Enable Unicode input and display when running Python from Windows console.
-
-[wordcloud]
-description = A little word cloud generator
-
-[wpca]
-description = Weighted Principal Component Analysis
-
-[wrapt]
-description = Module for decorators, wrappers and monkey patching.
-
-[wsgiref]
-description = WSGI (PEP 333) Reference Library
-
-[wsproto]
-description = WebSockets state-machine based protocol implementation
-
-[w3lib]
-description = Library of web-related functions
-
-[xarray]
-description = N-D labeled arrays and datasets in Python
-
-[xlrd]
-description = Library for developers to extract data from Microsoft Excel (tm) spreadsheet files
-
-[xlsxwriter]
-description = A Python module for creating Excel XLSX files.
-
-[xlwings]
-description = Make Excel fly: Interact with Excel from Python and vice versa.
-
-[xlwt]
-description = Library to create spreadsheet files compatible with MS Excel 97/2000/XP/2003 XLS files, on any platform, with Python 2.6, 2.7, 3.3+
-
-[xnd]
-description = General container that maps a wide range of Python values directly to memory.
-
-[xonsh]
-description = Python-powered, cross-platform, Unix-gazing shell
-
-[xray]
-description = N-D labeled arrays and datasets in Python
-
-[yapf]
-description = A formatter for Python code.
-
-[yarl]
-description = Yet another URL library
-
-[zarr]
-description = An implementation of chunked, compressed, N-dimensional arrays for Python.
-
-[zict]
-description = Mutable mapping tools
-
-[zipp]
-description = Backport of pathlib-compatible object wrapper for zip files
-
-[z3-solver]
-description = an efficient SMT solver library
-
-[umap-learn]
-description = Uniform Manifold Approximation and Projection
-
-[tensorboard-plugin-wit]
-description = What-If Tool TensorBoard plugin.
-
-[tbb]
-description = Intel(R) Threading Building Blocks
-
-[geemap]
-description = A Python package for interactive mapping using Google Earth Engine and ipyleaflet
-
-[earthengine-api]
-description = Earth Engine Python API
-
-[ipynb-py-convert]
-description = Convert .py files runnable in VSCode/Python or Atom/Hydrogen to jupyter .ipynb notebooks and vice versa
-
-[google-cloud-storage]
-description = Google Cloud Storage API client library
-
-[google-auth-httplib2]
-description = Google Authentication Library: httplib2 transport
-
-[httplib2shim]
-description = A wrapper over urllib3 that matches httplib2's interface
-
-[google-cloud-core]
-description = Google Cloud API client core library
-
-[google-resumable-media]
-description = Utilities for Google Media Downloads and Resumable Uploads
-
-[google-api-core]
-description = Google API client core library
-
-[googleapis-common-protos]
-description = Common protobufs used in Google APIs
-
-[pipenv]
-description = Python Development Workflow for Humans.
-
-[virtualenv-clone]
-description = script to clone virtualenvs.
-
-[virtualenv]
-description = Virtual Python Environment builder
-
-[distlib]
-description = Distribution utilities
-
-[flask-sqlalchemy]
-description = Adds SQLAlchemy support to your Flask application.
-
-[pipdeptree]
-description = Command line utility to show dependency tree of packages
-
-[flask-smorest]
-description = Flask/Marshmallow-based REST API framework
-
-[webargs]
-description = Declarative parsing and validation of HTTP request objects, with built-in support for popular web frameworks, including Flask, Django, Bottle, Tornado, Pyramid, webapp2, Falcon, and aiohttp.
-
-[pytest-trio]
-description = Pytest plugin for trio
-
-[poetry]
-description = Python dependency management and packaging made easy.
-
-[tomlkit]
-description = Style preserving TOML library
-
-[cachy]
-description = Cachy provides a simple yet effective caching library.
-
-[cachecontrol]
-description = httplib2 caching for requests
-
-[cleo]
-description = Cleo allows you to create beautiful and testable command-line interfaces.
-
-[shellingham]
-description = Tool to Detect Surrounding Shell
-
-[clikit]
-description = CliKit is a group of utilities to build beautiful and testable command line interfaces.
-
-[lockfile]
-description = Platform-independent file locking module
-
-[pylev]
-description = A pure Python Levenshtein implementation that's not freaking GPL'd.
-
-[pastel]
-description = Bring colors to your terminal.
-
-[mergedeep]
-description = A deep merge function for 🐍.
-
-[botorch]
-description = Bayesian Optimization in PyTorch
-
-[gpytorch]
-description = An implementation of Gaussian Processes in Pytorch
-
-[tifffile]
-description = Read and write TIFF(r) files
-
-[pooch]
-description = Pooch manages your Python library's sample data files: it automatically downloads and stores them in a local directory, with support for versioning and corruption checks.
-
-[imagecodecs]
-description = Image transformation, compression, and decompression codecs
-
-[threadpoolctl]
-description = threadpoolctl
-
-[nlopt]
-description = Library for nonlinear optimization, wrapping many algorithms for global and local, constrained or unconstrained, optimization
-
-[flaky]
-description = Plugin for nose or pytest that automatically reruns flaky tests.
-
-[pytest-qt]
-description = pytest support for PyQt and PySide applications
-
-[pytest-cov]
-description = Pytest plugin for measuring coverage.
-
-[pytest-ordering]
-description = pytest plugin to run your tests in a specific order
-
-[pytest-lazy-fixture]
-description = It helps to use fixtures in pytest.mark.parametrize
-
-[pytest-faulthandler]
-description = py.test plugin that activates the fault handler module for tests (dummy package)
-
-[pytest-mock]
-description = Thin-wrapper around the mock package for easier use with pytest
-
-[cachelib]
-description = A collection of cache libraries in the same API interface.
-
-[flask-session]
-description = Adds server-side session support to your Flask application
-
-[python-dotenv]
-description = Add .env support to your django/flask apps in development and deployments
-
-[httpie]
-description = HTTPie - a CLI, cURL-like tool for humans.
-
-[flask-mail]
-description = Flask extension for sending email
-
-[msvc-runtime]
-description = Install the Microsoft™ Visual C++™ runtime DLLs to the sys.prefix and Scripts directories
-
-[python-baseconv]
-description = Convert numbers from base 10 integers to base X strings and back again.
-
-[asgi-csrf]
-description = ASGI middleware for protecting against CSRF attacks
-
-[jupyter-bokeh]
-description = A Jupyter extension for rendering Bokeh content.
-
-[kaleido]
-description = Static image export for web-based visualization libraries with zero dependencies
-
-[pyftpdlib]
-description = Very fast asynchronous FTP server library
-
-[pysendfile]
-description = A Python interface to sendfile(2)
-
-[onnxruntime]
-description = ONNX Runtime Python bindings
-
-[dm-tree]
-description = Tree is a library for working with nested data structures.
-
-[amply]
-description = Amply allows you to load and manipulate AMPL/GLPK data as Python data structures
-
-[dask-glm]
-description = Generalized Linear Models with Dask
-
-[wasmer]
-description = Python extension to run WebAssembly binaries
-
-[jupyter-server-proxy]
-description = Jupyter server extension to supervise and proxy web services
-
-[iniconfig]
-description = iniconfig: brain-dead simple config-ini parsing
-
-[argon2-cffi]
-description = The secure Argon2 password hashing algorithm.
-
-[jinja2-time]
-description = Jinja2 Extension for Dates and Times
-
-[text-unidecode]
-description = The most basic Text::Unidecode port
-
-[ujson]
-description = Ultra fast JSON encoder and decoder for Python
-
-[scramp]
-description = An implementation of the SCRAM protocol.
-
-[nbclassic]
-description = Jupyter Notebook as a Jupyter Server Extension.
-
-[jupyterlab-git]
-description = A server extension for JupyterLab's git extension
-
-[gitdb]
-description = Git Object Database
-
-[slicer]
-description = A small package for big slicing.
-
-[jupyterlab-widgets]
-description = JupyterLab extension providing HTML widgets
-
-[mpl-interactions]
-description = Matplotlib aware interact functions
-
-[httpx]
-description = The next generation HTTP client.
-
-[httpcore]
-description = A minimal low-level HTTP client.
-
-[typer]
-description = Typer, build great CLIs. Easy to code. Based on Python type hints.
-
-[streamlit]
-description = The fastest way to build data apps in Python
-
-[pyqt5-tools]
-description = Tools to supplement the official PyQt5 wheels
-
-[ipygany]
-description = Scientific Visualization in Jupyter
-
-[pyvista]
-description = Easier Pythonic interface to VTK
-
-[scooby]
-description = A Great Dane turned Python environment detective
-
-[meshio]
-description = I/O for many mesh formats
-
-[dask-sql]
-description = Dask SQL
-
-[jpype1]
-description = A Python to Java bridge.
-
-[three-merge]
-description = Simple library for merging two strings with respect to a base one
-
-[pyls-spyder]
-description = Spyder extensions for the python-language-server
-
-[pyls-black]
-description = Black plugin for the Python Language Server
-
-[pysocks]
-description = A Python SOCKS client module. See https github.com/Anorov/PySocks for more information.
-
-[pyinstaller-hooks-contrib]
-description = Community maintained hooks for PyInstaller
-
-[nbval]
-description = A py.test plugin to validate Jupyter notebooks
-
-[jupyterlab-classic]
-description = The next gen old-school Notebook UI
-
-[sklearn-contrib-lightning]
-description = Large-scale sparse linear classification, regression and ranking in Python
-
-[textdistance]
-description = Compute distance between the two texts.
-
-[siphon]
-description = A collection of Python utilities for interacting with the Unidata technology stack.
-
-[et-xmlfile]
-description = An implementation of lxml.xmlfile for the standard library
-
-[jdcal]
-description = Julian dates from proleptic Gregorian and Julian calendars.
-
-[orjson]
-description = Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy
-
-[zstandard]
-description = Zstandard bindings for Python
-
-[wasmer-compiler-cranelift]
-description = The Cranelift compiler for the `wasmer` package (to compile WebAssembly module)
-
-[jupyterlab-lsp]
-description = Language Server Protocol integration for JupyterLab
-
-[jupyter-lsp]
-description = Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server
-
-[wasmer-compiler-singlepass]
-description = Python extension to run WebAssembly binaries
-
-[napari]
-description = n-dimensional array viewer in Python
-
-[napari-svg]
-description = A plugin for reading and writing svg files with napari
-
-[napari-plugin-engine]
-description = napari plugin engine, fork of pluggy
-
-[magicgui]
-description = build GUIs from functions, using magic.
-
-[freetype-py]
-description = Freetype python bindings
-
-[cachey]
-description = Caching mindful of computation/storage costs
-
-[pynndescent]
-description = Nearest Neighbor Descent
-
-[torchaudio]
-description = An audio package for PyTorch
-
-[napari-console]
-description = A plugin that adds a console to napari
-
-[docstring-parser]
-description = UNKNOWN
-
-[pendulum]
-description = Python datetimes made easy.
-
-[toposort]
-description = Implements a topological sort algorithm.
-
-[python-editor]
-description = Programmatically open an editor, capture the result.
-
-[natsort]
-description = Simple yet flexible natural sorting in Python.
-
-[grpcio-health-checking]
-description = Standard Health Checking Service for gRPC
-
-[dagster]
-description = A data orchestrator for machine learning, analytics, and ETL.
-
-[croniter]
-description = croniter provides iteration for datetime object with cron like format
-
-[alembic]
-description = A database migration tool for SQLAlchemy.
-
-[skl2onnx]
-description = Convert scikit-learn models to ONNX
-
-[onnxconverter-common]
-description = ONNX Converter and Optimization Tools
-
-[onnx]
-description = Open Neural Network Exchange
-
-[graphql-ws]
-description = Websocket server for GraphQL subscriptions
-
-[gevent]
-description = Coroutine-based network library
-
-[gevent-websocket]
-description = Websocket handler for the gevent pywsgi server, a Python network library
-
-[flask-sockets]
-description = Elegant WebSockets for your Flask apps.
-
-[flask-graphql]
-description = Adds GraphQL support to your Flask application
-
-[dagster-graphql]
-description = The GraphQL frontend to python dagster.
-
-[dagit]
-description = Web UI for dagster.
-
-[snowflake-connector-python]
-description = Snowflake Connector for Python
-
-[pytimeparse]
-description = Time expression parser
-
-[python-slugify]
-description = A Python Slugify application that handles Unicode
-
-[pyjwt]
-description = JSON Web Token implementation in Python
-
-[pycryptodomex]
-description = Cryptographic library for Python
-
-[psycopg2-binary]
-description = psycopg2 - Python-PostgreSQL Database Adapter
-
-[proto-plus]
-description = Beautiful, Pythonic protocol buffers.
-
-[parsedatetime]
-description = Parse human-readable date/time text.
-
-[oscrypto]
-description = TLS (SSL) sockets, key generation, encryption, decryption, signing, verification and KDFs using the OS crypto libraries. Does not require a compiler, and relies on the OS for patching. Works on Windows, OS X and Linux/BSD.
-
-[msrest]
-description = AutoRest swagger generator Python client runtime.
-
-[minimal-snowplow-tracker]
-description = A minimal snowplow event tracker for Python. Add analytics to your Python and Django apps, webapps and games
-
-[logbook]
-description = A logging replacement for Python
-
-[json-rpc]
-description = JSON-RPC transport implementation
-
-[isodate]
-description = An ISO 8601 date/time/duration parser and formatter
-
-[hologram]
-description = JSON schema generation from dataclasses
-
-[google-crc32c]
-description = A python wrapper of the C library 'Google CRC32C'
-
-[google-cloud-bigquery]
-description = Google BigQuery API client library
-
-[dbt]
-description = With dbt, data analysts and engineers can build analytics the way engineers build applications.
-
-[dbt-snowflake]
-description = The snowflake adapter plugin for dbt (data build tool)
-
-[dbt-redshift]
-description = The redshift adapter plugin for dbt (data build tool)
-
-[dbt-postgres]
-description = The postgres adpter plugin for dbt (data build tool)
-
-[dbt-core]
-description = dbt (data build tool) is a command line tool that helps analysts and engineers transform data in their warehouse more effectively
-
-[dbt-bigquery]
-description = The bigquery adapter plugin for dbt (data build tool)
-
-[azure-storage-blob]
-description = Microsoft Azure Blob Storage Client Library for Python
-
-[azure-core]
-description = Microsoft Azure Core Library for Python
-
-[azure-common]
-description = Microsoft Azure Client Library for Python (Common)
-
-[agate]
-description = A data analysis library that is optimized for humans instead of machines.
-
-[nteract-scrapbook]
-description = A library for recording and reading data in Jupyter and nteract Notebooks
-
-[jsonpointer]
-description = Identify specific nodes in a JSON document (RFC 6901)
-
-[jsonpatch]
-description = Apply JSON-Patches (RFC 6902)
-
-[great-expectations]
-description = Always know what to expect from your data.
-
-[dagstermill]
-description = run notebooks using the Dagster tools
-
-[websocket-client]
-description = WebSocket client for Python. hybi13 is supported.
-
-[python-box]
-description = Advanced Python dictionaries with dot notation access
-
-[prefect]
-description = The Prefect Core automation and scheduling engine.
-
-[marshmallow-oneofschema]
-description = marshmallow multiplexing schema
-
-[docker]
-description = A Python library for the Docker Engine API.
-
-[pyerfa]
-description = Python bindings for ERFA
-
-[jupyter-packaging]
-description = Jupyter Packaging Utilities
-
-[aiomultiprocess]
-description = asyncio version of the standard multiprocessing module
-
-[nbtutor]
-description = Visualize Python code execution in Jupyter Notebook cells
-
-[tinycss]
-description = tinycss is a complete yet simple CSS parser for Python.
-
-[qstylizer]
-description = Stylesheet Generator for PyQt{4-5}/PySide{1-2}
-
-[inflection]
-description = A port of Ruby on Rails inflector to Python
-
-[arrow]
-description = Better dates & times for Python
-
-[quadprog]
-description = Quadratic Programming Solver
-
-[qpsolvers]
-description = Quadratic programming solvers in Python with a unified API
-
-[flit-core]
-description = Distribution-building parts of Flit. See flit package for more information
-
-[swift-sim]
-description = A Python/Javascript Visualiser
-
-[spatialmath-python]
-description = Provides spatial maths capability for Python.
-
-[spatialgeometry]
-description = A Shape and Geometry Package
-
-[rtb-data]
-description = Data files for the Robotics Toolbox for Python.
-
-[roboticstoolbox-python]
-description = A Python library for robotic education and research
-
-[pgraph-python]
-description = Simple graph functionality for Python.
-
-[colored]
-description = Simple library for color and formatting to terminal
-
-[ansitable]
-description = Quick and easy display of tabular data and matrices with optional ANSI color and borders.
-
-[qdldl]
-description = QDLDL, a free LDL factorization routine.
-
-[jupyter-server-mathjax]
-description = MathJax resources as a Jupyter Server Extension.
-
-[voila-gridstack]
-description = A GridStack template for Voila.
-
-[deprecation]
-description = A library to handle automated deprecations
-
-[matplotlib-inline]
-description = Inline Matplotlib backend for Jupyter
-
-[sqlite-utils]
-description = CLI tool and Python utility functions for manipulating SQLite databases
-
-[py-lru-cache]
-description = LRU cache for python. Provides a dictionary-like object as well as a method decorator.
-
-[dateparser]
-description = Date parsing library designed to parse dates from HTML pages
-
-[datasette-graphql]
-description = Datasette plugin providing an automatic GraphQL API for your SQLite databases
-
-[csvs-to-sqlite]
-description = Convert CSV files into a SQLite database
-
-[readline]
-description = Hack to make "pip install readline" happy and do nothing
-
-[python-picard]
-description = Preconditoned ICA for Real Data
-
-[maturin]
-description = Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages
-
-[cached-property]
-description = A decorator for caching properties in classes.
-
-[tinycss2]
-description = tinycss2
-
-[slicerator]
-description = A lazy-loading, fancy-sliceable iterable.
-
-[pims]
-description = Python Image Sequence
-
-[flatbuffers]
-description = The FlatBuffers serialization format for Python
-
-[dask-image]
-description = Distributed image processing
-
-[wasabi]
-description = A lightweight console printing and formatting toolkit
-
-[srsly]
-description = Modern high-performance serialization utilities for Python
-
-[spacy-legacy]
-description = Legacy registered functions for spaCy backwards compatibility
-
-[smart-open]
-description = Utils for streaming large files (S3, HDFS, GCS, Azure Blob Storage, gzip, bz2...)
-
-[pathy]
-description = pathlib.Path subclasses for local and cloud bucket storage
-
-[fastcore]
-description = Python supercharged for fastai development
-
-[catalogue]
-description = Super lightweight function registries for your library
-
-[blis]
-description = The Blis BLAS-like linear algebra library, as a self-contained C-extension.
-
-[requests-unixsocket]
-description = Use requests to talk HTTP via a UNIX domain socket
-
-[platformdirs]
-description = A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir".
-
-[debugpy]
-description = An implementation of the Debug Adapter Protocol for Python
-
-[charset-normalizer]
-description = The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.
-
-[backports-entry-points-selectable]
-description = Compatibility shim providing selectable entry points for older implementations
-
-[sqlite-fts4]
-description = Python functions for working with SQLite FTS4 search
-
-[pyzstd]
-description = Python bindings to Zstandard (zstd) compression library, the API is similar to Python's bz2/lzma/zlib module.
-
-[pypyodbc]
-description = A Pure Python ctypes ODBC module
-
-[jupyter-dash]
-description = Dash support for the Jupyter notebook interface
-
-[ansi2html]
-description = UNKNOWN
-
-[tomli]
-description = A lil' TOML parser
-
-[python-lsp-server]
-description = Python Language Server for the Language Server Protocol
-
-[python-lsp-jsonrpc]
-description = JSON RPC 2.0 server library
-
-[python-lsp-black]
-description = Black plugin for the Python LSP Server
-
-[cramjam]
-description = Thin Python bindings to de/compression algorithms in Rust
-
-[rich]
-description = Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal
-
-[fastdownload]
-description = A general purpose data downloading library.
-
-[dateutils]
-description = Various utilities for working with date and datetime objects
-
-[shiboken6]
-description = Python / C++ bindings helper module
-
-[setuptools-scm]
-description = the blessed package to manage your versions by scm tags
-
-[pyside6]
-description = Python bindings for the Qt cross-platform application and UI framework
-
-[jellyfish]
-description = a library for doing approximate and phonetic matching of strings.
-
-[tomli-w]
-description = A lil' TOML writer
-
-[frozenlist]
-description = A list-like structure which implements collections.abc.MutableSequence
-
-[aiosignal]
-description = aiosignal: a list of registered asynchronous callbacks
-
-[parsy]
-description = easy-to-use parser combinators, for parsing in pure Python
-
-[argon2-cffi-bindings]
-description = Low-level CFFI bindings for Argon2
-
-[clr-loader]
-description = Generic pure Python loader for .NET runtimes
-
-[cx-logging]
-description = Python and C interfaces for logging
-
-[tzdata]
-description = Provider of IANA time zone data
-
-[pytz-deprecation-shim]
-description = Shims to make deprecation of pytz easier
-
-[asttokens]
-description = Annotate AST trees with source code positions
-
-[executing]
-description = Get the currently executing AST node of a frame, and other information
-
-[pure-eval]
-description = Safely evaluate AST nodes without side effects
-
-[stack-data]
-description = Extract data from python stack frames and tracebacks for informative displays
-
-[langcodes]
-description = Tools for labeling human languages with IETF language tags
-
-[spacy-loggers]
-description = Logging utilities for SpaCy
-
-[hpy]
-description = A better C API for Python
-
-[doit]
-description = doit - Automation Tool
-
-[jupyterlite]
-description = tools for building JupyterLite sites
-
-[pyqt5-qt5]
-description = The subset of a Qt installation needed by PyQt5.
-
-[pyqtwebengine-qt5]
-description = The subset of a Qt installation needed by PyQtWebEngine.
-
-[superqt]
-description = Missing widgets for PyQt/PySide
-
-[notebook-shim]
-description = A shim layer for notebook traits and config
-
-[pygad]
-description = PyGAD: A Python 3 Library for Building the Genetic Algorithm and Training Machine Learning Algoithms (Keras & PyTorch).
-
-[fastjsonschema]
-description = Fastest Python implementation of JSON schema
-
-[httptools]
-description = A collection of framework independent HTTP protocol utils.
-
-[pyside6-addons]
-description = Python bindings for the Qt cross-platform application and UI framework (Addons)
-
-[pyside6-essentials]
-description = Python bindings for the Qt cross-platform application and UI framework (Essentials)
-
-[importlib-resources]
-description = Read resources from Python packages
-
-[argparse]
-description = Python command-line parsing library
-
-[traceback2]
-description = Backports of the traceback module
-
-[unittest2]
-description = The new features in unittest backported to Python 2.4+.
-
-[linecache2]
-description = Backports of the linecache module
-
-[django]
-description = A high-level Python web framework that encourages rapid development and clean, pragmatic design.
-
-[watchgod]
-description = Simple, modern file watching and code reload in python.
-
-[deap]
-description = Distributed Evolutionary Algorithms in Python
-
-[backports-zoneinfo]
-description = Backport of the standard library zoneinfo module
-
-[lief]
-description = Library to instrument executable formats
-
-[polars]
-description = Blazingly fast DataFrame library
-
-[xyzservices]
-description = Source of XYZ tiles providers
-
-[filterpy]
-description = Kalman filtering and optimal estimation library
-
-[zstd]
-description = ZSTD Bindings for Python
-
-[pmdarima]
-description = Python's forecast::auto.arima equivalent
-
-[pytoolconfig]
-description = Python tool configuration
-
-[tbats]
-description = BATS and TBATS for time series forecasting
-
-[ntlm-auth]
-description = Creates NTLM authentication structures
-
-[requests-ntlm]
-description = This package allows for HTTP NTLM authentication using the requests library.
-
-[sspyrs]
-description = Lightweight interface for SSRS reports to python
-
-[xmltodict]
-description = Makes working with XML feel like you are working with JSON
-
-[missingno]
-description = Missing data visualization module for Python.
-
-[intel-openmp]
-description = Intel OpenMP* Runtime Library
-
-[mkl]
-description = Intel oneAPI Math Kernel Library
-
-[whatthepatch]
-description = A patch parsing and application library.
-
-[duckdb]
-description = DuckDB embedded database
-
-[ffmpy]
-description = A simple Python wrapper for ffmpeg
-
-[pyqt6-sip]
-description = The sip module support for PyQt6
-
-[pyqt6]
-description = Python bindings for the Qt cross platform application toolkit
-
-[pyqt6-qt6]
-description = The subset of a Qt installation needed by PyQt6.
-
-[xgboost]
-description = XGBoost Python Package
-
-[click-default-group-wheel]
-description = Extends click.Group to invoke a command without explicit subcommand name (packaged as a wheel)
-
-[exceptiongroup]
-description = Backport of PEP 654 (exception groups)
-
-[linear-operator]
-description = A linear operator implementation, primarily designed for finite-dimensional positive definite operators (i.e. kernel matrices).
-
-[waitress]
-description = Waitress WSGI server
-
-[contourpy]
-description = Python library for calculating contours of 2D quadrilateral grids
-
diff --git a/winpython/data/tools.ini b/winpython/data/tools.ini
deleted file mode 100644
index 0f27fc8f..00000000
--- a/winpython/data/tools.ini
+++ /dev/null
@@ -1,47 +0,0 @@
-[gettext]
-description=GNU gettext Win32 porting - the GNU translation tool (useful tools for pygettext, a standard library module)
-url=https://sourceforge.net/projects/gettext
-
-[julia]
-description=The Julia Langage
-url=https://julialang.org/
-
-[mingw32]
-description=C/C++ and Fortran compilers (Mingwpy static toolchain version)
-url=https://github.com/numpy/numpy/wiki/Mingw-static-toolchain
-
-[pandoc]
-description=a universal document converter
-url=https://pandoc.org/
-
-[r]
-description=The R Project for Statistical Computing
-url=https://www.r-project.org
-
-[scite]
-description=SCIntilla based Text Editor - Multilanguage, powerful and light-weight text editor
-url=http://www.scintilla.org/SciTE.html
-
-[tortoisehg]
-description=Set of graphical tools and a shell extension for the Mercurial distributed revision control system
-url=https://tortoisehg.bitbucket.io/
-
-[winmerge]
-description=Open Source differencing and merging tool for Windows
-url=http://winmerge.org
-
-[nodejs]
-description=a JavaScript runtime built on Chrome's V8 JavaScript engine
-url=https://nodejs.org
-
-[npmjs]
-description=a package manager for JavaScript
-url=https://www.npmjs.com/
-
-[yarnpkg]
-description=a package manager for JavaScriptFast, reliable, and secure dependency management
-url=https://yarnpkg.com/lang/en/
-
-[ffmpeg]
-description=a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata
-url=https://ffmpeg.org
diff --git a/winpython/disthelpers.py b/winpython/disthelpers.py
deleted file mode 100644
index b9ea06b5..00000000
--- a/winpython/disthelpers.py
+++ /dev/null
@@ -1,950 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2009-2011 CEA
-# Pierre Raybaut
-# Licensed under the terms of the CECILL License
-# (see guidata/__init__.py for details)
-
-# pylint: disable=W0613
-
-"""
-disthelpers
------------
-
-The ``guidata.disthelpers`` module provides helper functions for Python
-package distribution on Microsoft Windows platforms with ``py2exe`` or on
-all platforms thanks to ``cx_Freeze``.
-"""
-
-from __future__ import print_function
-
-import sys
-import os
-import os.path as osp
-from pathlib import Path
-import shutil
-import traceback
-import atexit
-import imp
-from subprocess import Popen, PIPE
-import warnings
-from distutils.version import LooseVersion, StrictVersion
-
-# ==============================================================================
-# Module, scripts, programs
-# ==============================================================================
-def get_module_path(modname):
- """Return module *modname* base path"""
- module = sys.modules.get(modname, __import__(modname))
- return osp.abspath(osp.dirname(module.__file__))
-
-
-# ==============================================================================
-# Dependency management
-# ==============================================================================
-def get_changeset(path, rev=None):
- """Return Mercurial repository *path* revision number"""
- args = ['hg', 'parent']
- if rev is not None:
- args += ['--rev', str(rev)]
- process = Popen(
- args, stdout=PIPE, stderr=PIPE, cwd=path, shell=True
- )
- try:
- return (
- process.stdout.read().splitlines()[0].split()[1]
- )
- except IndexError:
- raise RuntimeError(process.stderr.read())
-
-
-def prepend_module_to_path(module_path):
- """
- Prepend to sys.path module located in *module_path*
- Return string with module infos: name, revision, changeset
-
- Use this function:
- 1) In your application to import local frozen copies of internal libraries
- 2) In your py2exe distributed package to add a text file containing the returned string
- """
- if not osp.isdir(module_path):
- # Assuming py2exe distribution
- return
- sys.path.insert(0, osp.abspath(module_path))
- changeset = get_changeset(module_path)
- name = osp.basename(module_path)
- prefix = "Prepending module to sys.path"
- message = prefix + (
- "%s [revision %s]" % (name, changeset)
- ).rjust(80 - len(prefix), ".")
- print(message, file=sys.stderr)
- if name in sys.modules:
- sys.modules.pop(name)
- nbsp = 0
- for modname in sys.modules.keys():
- if modname.startswith(name + '.'):
- sys.modules.pop(modname)
- nbsp += 1
- warning = '(removed %s from sys.modules' % name
- if nbsp:
- warning += ' and %d subpackages' % nbsp
- warning += ')'
- print(warning.rjust(80), file=sys.stderr)
- return message
-
-
-def prepend_modules_to_path(module_base_path):
- """Prepend to sys.path all modules located in *module_base_path*"""
- if not osp.isdir(module_base_path):
- # Assuming py2exe distribution
- return
- fnames = [
- # osp.join(module_base_path, name)
- str(Path(module_base_path) / name)
- for name in os.listdir(module_base_path)
- ]
- messages = [
- prepend_module_to_path(dirname)
- for dirname in fnames
- if osp.isdir(dirname)
- ]
- return os.linesep.join(messages)
-
-
-# ==============================================================================
-# Distribution helpers
-# ==============================================================================
-def _remove_later(fname):
- """Try to remove file later (at exit)"""
-
- def try_to_remove(fname):
- if osp.exists(fname):
- os.remove(fname)
-
- atexit.register(try_to_remove, osp.abspath(fname))
-
-
-def to_include_files(data_files):
- """Convert data_files list to include_files list
-
- data_files:
- * this is the ``py2exe`` data files format
- * list of tuples (dest_dirname, (src_fname1, src_fname2, ...))
-
- include_files:
- * this is the ``cx_Freeze`` data files format
- * list of tuples ((src_fname1, dst_fname1),
- (src_fname2, dst_fname2), ...))
- """
- include_files = []
- for dest_dir, fnames in data_files:
- for source_fname in fnames:
- #dest_fname = osp.join(
- # dest_dir, osp.basename(source_fname))
- dest_fname = str(Path(dest_dir) /
- osp.basename(source_fname))
- include_files.append((source_fname, dest_fname))
- return include_files
-
-
-def strip_version(version):
- """Return version number with digits only
- (Windows does not support strings in version numbers)"""
- return (
- version.split('beta')[0]
- .split('alpha')[0]
- .split('rc')[0]
- .split('dev')[0]
- )
-
-
-def remove_dir(dirname):
- """Remove directory *dirname* and all its contents
- Print details about the operation (progress, success/failure)"""
- print("Removing directory '%s'..." % dirname, end=' ')
- try:
- shutil.rmtree(dirname, ignore_errors=True)
- print("OK")
- except Exception:
- print("Failed!")
- traceback.print_exc()
-
-
-class Distribution(object):
- """Distribution object
-
- Help creating an executable using ``py2exe`` or ``cx_Freeze``
- """
-
- DEFAULT_EXCLUDES = [
- 'Tkconstants',
- 'Tkinter',
- 'tcl',
- 'tk',
- 'wx',
- '_imagingtk',
- 'curses',
- 'PIL._imagingtk',
- 'ImageTk',
- 'PIL.ImageTk',
- 'FixTk',
- 'bsddb',
- 'email',
- 'pywin.debugger',
- 'pywin.debugger.dbgcon',
- 'matplotlib',
- ]
- DEFAULT_INCLUDES = []
- DEFAULT_BIN_EXCLUDES = [
- 'MSVCP100.dll',
- 'MSVCP90.dll',
- 'w9xpopen.exe',
- 'MSVCP80.dll',
- 'MSVCR80.dll',
- ]
- DEFAULT_BIN_INCLUDES = []
- DEFAULT_BIN_PATH_INCLUDES = []
- DEFAULT_BIN_PATH_EXCLUDES = []
-
- def __init__(self):
- self.name = None
- self.version = None
- self.description = None
- self.target_name = None
- self._target_dir = None
- self.icon = None
- self.data_files = []
- self.includes = self.DEFAULT_INCLUDES
- self.excludes = self.DEFAULT_EXCLUDES
- self.bin_includes = self.DEFAULT_BIN_INCLUDES
- self.bin_excludes = self.DEFAULT_BIN_EXCLUDES
- self.bin_path_includes = (
- self.DEFAULT_BIN_PATH_INCLUDES
- )
- self.bin_path_excludes = (
- self.DEFAULT_BIN_PATH_EXCLUDES
- )
- self.msvc = os.name == 'nt'
- self._py2exe_is_loaded = False
- self._pyqt4_added = False
- self._pyside_added = False
- # Attributes relative to cx_Freeze:
- self.executables = []
-
- @property
- def target_dir(self):
- """Return target directory (default: 'dist')"""
- dirname = self._target_dir
- if dirname is None:
- return 'dist'
- else:
- return dirname
-
- @target_dir.setter # analysis:ignore
- def target_dir(self, value):
- self._target_dir = value
-
- def setup(
- self,
- name,
- version,
- description,
- script,
- target_name=None,
- target_dir=None,
- icon=None,
- data_files=None,
- includes=None,
- excludes=None,
- bin_includes=None,
- bin_excludes=None,
- bin_path_includes=None,
- bin_path_excludes=None,
- msvc=None,
- ):
- """Setup distribution object
-
- Notes:
- * bin_path_excludes is specific to cx_Freeze (ignored if it's None)
- * if msvc is None, it's set to True by default on Windows
- platforms, False on non-Windows platforms
- """
- self.name = name
- self.version = (
- strip_version(version)
- if os.name == 'nt'
- else version
- )
- self.description = description
- assert osp.isfile(script)
- self.script = script
- self.target_name = target_name
- self.target_dir = target_dir
- self.icon = icon
- if data_files is not None:
- self.data_files += data_files
- if includes is not None:
- self.includes += includes
- if excludes is not None:
- self.excludes += excludes
- if bin_includes is not None:
- self.bin_includes += bin_includes
- if bin_excludes is not None:
- self.bin_excludes += bin_excludes
- if bin_path_includes is not None:
- self.bin_path_includes += bin_path_includes
- if bin_path_excludes is not None:
- self.bin_path_excludes += bin_path_excludes
- if msvc is not None:
- self.msvc = msvc
- if self.msvc:
- try:
- pass # manage via msvc_runtime wheel (or give up anyway)
- # self.data_files += create_msvc_data_files()
- except IOError:
- print(
- "Setting the msvc option to False "
- "will avoid this error",
- file=sys.stderr,
- )
- raise
- # cx_Freeze:
- self.add_executable(
- self.script, self.target_name, icon=self.icon
- )
-
- def add_text_data_file(self, filename, contents):
- """Create temporary data file *filename* with *contents*
- and add it to *data_files*"""
- open(filename, 'wb').write(contents)
- self.data_files += [("", (filename,))]
- _remove_later(filename)
-
- def add_data_file(self, filename, destdir=''):
- self.data_files += [(destdir, (filename,))]
-
- # ------ Adding packages
- def add_pyqt4(self):
- """Include module PyQt4 to the distribution"""
- if self._pyqt4_added:
- return
- self._pyqt4_added = True
-
- self.includes += [
- 'sip',
- 'PyQt4.Qt',
- 'PyQt4.QtSvg',
- 'PyQt4.QtNetwork',
- ]
-
- import PyQt4
-
- pyqt_path = osp.dirname(PyQt4.__file__)
-
- # Configuring PyQt4
- conf = os.linesep.join(
- ["[Paths]", "Prefix = .", "Binaries = ."]
- )
- self.add_text_data_file('qt.conf', conf)
-
- # Including plugins (.svg icons support, QtDesigner support, ...)
- if self.msvc:
- vc90man = "Microsoft.VC90.CRT.manifest"
- pyqt_tmp = 'pyqt_tmp'
- if osp.isdir(pyqt_tmp):
- shutil.rmtree(pyqt_tmp)
- os.mkdir(pyqt_tmp)
- # vc90man_pyqt = osp.join(pyqt_tmp, vc90man)
- vc90man_pyqt = str(Path(pyqt_tmp) / vc90man)
- man = (
- open(vc90man, "r")
- .read()
- .replace(
- '
-
-
-
diff --git a/winpython/make.py b/winpython/make.py
new file mode 100644
index 00000000..437a8042
--- /dev/null
+++ b/winpython/make.py
@@ -0,0 +1,174 @@
+# -*- coding: utf-8 -*-
+#
+# WinPython build script
+# Copyright © 2012 Pierre Raybaut
+# Copyright © 2014-2025+ The Winpython development team https://github.com/winpython/
+# Licensed under the terms of the MIT License
+# (see wppm/__init__.py for details)
+
+import os
+import re
+import shutil
+from pathlib import Path
+from wppm import wppm, utils
+
+PORTABLE_DIRECTORY = Path(__file__).parent / "portable"
+assert PORTABLE_DIRECTORY.is_dir(), f"Portable directory not found: {PORTABLE_DIRECTORY}"
+
+def copy_items(source_directories: list[Path], target_directory: Path, verbose: bool = False):
+ """Copies items from source directories to the target directory."""
+ target_directory.mkdir(parents=True, exist_ok=True)
+ for source_dir in source_directories:
+ if not source_dir.is_dir():
+ print(f"Warning: Source directory not found: {source_dir}")
+ continue
+ for source_item in source_dir.iterdir():
+ target_item = target_directory / source_item.name
+ copy_function = shutil.copytree if source_item.is_dir() else shutil.copy2
+ try:
+ copy_function(source_item, target_item)
+ if verbose:
+ print(f"Copied: {source_item} -> {target_item}")
+ except Exception as e:
+ print(f"Error copying {source_item} to {target_item}: {e}")
+
+def parse_list_argument(argument_value: str | list[str], separator=" ") -> list[str]:
+ """Parse a separated list argument into a list of strings."""
+ if not argument_value: return []
+ return argument_value.split(separator) if isinstance(argument_value, str) else list(argument_value)
+
+class WinPythonDistributionBuilder:
+ """Builds a WinPython distribution."""
+
+ def __init__(self, build_number: int, release_level: str, basedir_wpy: Path,
+ source_dirs: Path, tools_directories: list[Path] = None,
+ verbose: bool = False, flavor: str = ""):
+ """
+ Initializes the WinPythonDistributionBuilder.
+ Args:
+ build_number: The build number (integer).
+ release_level: The release level (e.g., "beta", "").
+ basedir_wpy: top directory of the build (c:\...\Wpy...)
+ source_dirs: Directory containing wheel files for packages.
+ tools_directories: List of directories containing development tools to include.
+ verbose: Enable verbose output.
+ flavor: WinPython flavor (e.g., "Barebone").
+ """
+ self.build_number = build_number
+ self.release_level = release_level
+ self.winpython_directory = Path(basedir_wpy)
+ self.target_directory = self.winpython_directory.parent
+ self.source_dirs = Path(source_dirs)
+ self.tools_directories = tools_directories or []
+ self.verbose = verbose
+ self.distribution: wppm.Distribution | None = None
+ self.flavor = flavor
+ self.python_zip_file: Path = self._get_python_zip_file()
+ self.python_name = self.python_zip_file.stem
+ self.python_directory_name = "python"
+
+ def _get_python_zip_file(self) -> Path:
+ """Finds the Python .zip file in the wheels directory."""
+ for source_item in self.source_dirs.iterdir():
+ if re.match(r"(pypy3|python-).*\.zip", source_item.name):
+ return source_item
+ raise RuntimeError(f"Could not find Python zip package in {self.source_dirs}")
+
+ @property
+ def winpython_version_name(self) -> str:
+ """Returns the full WinPython version string."""
+ return f"{self.python_full_version}.{self.build_number}{self.flavor}{self.release_level}"
+
+ @property
+ def python_full_version(self) -> str:
+ """Retrieves the Python full version string from the distribution."""
+ return utils.get_python_long_version(self.distribution.target) if self.distribution else "0.0.0"
+
+ def _print_action(self, text: str):
+ """Prints an action message with progress indicator."""
+ utils.print_box(text) if self.verbose else print(f"{text}...", end="", flush=True)
+
+ def _extract_python_archive(self):
+ """Extracts the Python zip archive to create the base Python environment."""
+ self._print_action("Extracting Python archive")
+ utils.extract_archive(self.python_zip_file, self.winpython_directory)
+ # Relocate to /python subfolder if needed (for newer structure) #2024-12-22 to /python
+ expected_python_directory = self.winpython_directory / self.python_directory_name
+ if self.python_directory_name != self.python_name and not expected_python_directory.is_dir():
+ os.rename(self.winpython_directory / self.python_name, expected_python_directory)
+
+ def _copy_essential_files(self):
+ """Copies pre-made objects"""
+ self._print_action("Copying launchers")
+ copy_items([PORTABLE_DIRECTORY / "launchers_final"], self.winpython_directory, self.verbose)
+
+ tools_target_directory = self.winpython_directory / "t"
+ self._print_action(f"Copying tools to {tools_target_directory}")
+ copy_items(self.tools_directories, tools_target_directory, self.verbose)
+
+ def _create_env_config(self):
+ """Creates environment setup"""
+ executable_name = self.distribution.short_exe if self.distribution else "python.exe"
+ config = {
+ "WINPYthon_exe": executable_name,
+ "WINPYthon_subdirectory_name": self.python_directory_name,
+ "WINPYVER": self.winpython_version_name,
+ "WINPYVER2": f"{self.python_full_version}.{self.build_number}",
+ "WINPYFLAVOR": self.flavor,
+ "WINPYARCH": self.distribution.architecture if self.distribution else 64,
+ }
+ env_path = self.winpython_directory / "scripts" / "env.ini"
+ env_path.parent.mkdir(parents=True, exist_ok=True)
+ self._print_action(f"Creating env.ini environment {env_path}")
+ env_path.write_text("\n".join(f"{k}={v}" for k, v in config.items()))
+
+ def build(self):
+ """Make or finalise WinPython distribution in the target directory"""
+ print(f"Building WinPython with Python archive: {self.python_zip_file.name}")
+ self._print_action(f"Creating WinPython {self.winpython_directory} base directory")
+ if self.winpython_directory.is_dir() and len(self.winpython_directory.parts)>=4:
+ shutil.rmtree(self.winpython_directory)
+ # preventive re-Creation of settings directory
+ (self.winpython_directory / "settings" / "AppData" / "Roaming").mkdir(parents=True, exist_ok=True)
+
+ self._extract_python_archive()
+ self.distribution = wppm.Distribution(self.winpython_directory / self.python_directory_name, verbose=self.verbose)
+ self._copy_essential_files()
+ self._create_env_config()
+
+def make_all(build_number: int, release_level: str, basedir_wpy: Path = None,
+ source_dirs: Path = None, toolsdirs: str | list[Path] = None,
+ verbose: bool = False, flavor: str = ""):
+ """
+ Make a WinPython distribution for a given set of parameters:
+ Args:
+ build_number: build number [int]
+ release_level: release level (e.g. 'beta1', '') [str]
+ basedir_wpy: top directory of the build (c:\...\Wpy...)
+ verbose: Enable verbose output (bool).
+ flavor: WinPython flavor (str).
+ source_dirs: the python.zip
+ toolsdirs: Directory with development tools r'D:\WinPython\basedir34\t.Slim'
+ """
+ assert basedir_wpy is not None, "The *winpython_dirname* directory must be specified"
+
+ tools_directories = [Path(d) for d in parse_list_argument(toolsdirs, ",")]
+ utils.print_box(f"Making WinPython at {basedir_wpy}")
+ os.makedirs(basedir_wpy, exist_ok=True)
+
+ builder = WinPythonDistributionBuilder(
+ build_number, release_level, Path(basedir_wpy),
+ verbose=verbose, flavor=flavor,
+ source_dirs=source_dirs, tools_directories=tools_directories)
+ builder.build()
+
+if __name__ == "__main__":
+ make_all(
+ build_number=1,
+ release_level="b3",
+ basedir_wpy=r"D:\WinPython\bd314\budot\WPy64-31401b3",
+ verbose=True,
+ flavor="dot",
+ source_dirs=r"D:\WinPython\bd314\packages.win-amd64",
+ toolsdirs=r"D:\WinPython\bd314\t.Slim",
+ )
diff --git a/winpython/piptree.py b/winpython/piptree.py
deleted file mode 100644
index e44fdca1..00000000
--- a/winpython/piptree.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# -*- coding: utf-8 -*-
-import json, sys, re, platform, os
-import re
-from winpython import utils
-from collections import OrderedDict
-from pip._vendor.packaging.markers import Marker
-
-
-def normalize(this):
- """apply https://peps.python.org/pep-0503/#normalized-names"""
- return re.sub(r"[-_.]+", "-", this).lower()
-
-
-class pipdata:
- """Wrapper aroud pip inspect"""
-
- def __init__(self):
-
- # get pip_inpsect raw data in json form
- pip_inspect = utils.exec_run_cmd(["pip", "inspect"])
- pip_json = json.loads(pip_inspect)
-
- # create a distro{} dict of Packages
- # key = normalised package name
- # string_elements = 'name', 'version', 'summary'
- # requires = list of dict with 1 level need downward
- # req_key = package_key requires
- # req_extra = extra branch needed of the package_key ('all' or '')
- # req_version = version needed
- # req_marker = marker of the requirement (if any)
- self.distro = {}
- replacements = str.maketrans({" ": "", "[": "", "]": "", "'": "", '"': ""})
- self.environment = {
- "implementation_name": sys.implementation.name,
- "implementation_version": "{0.major}.{0.minor}.{0.micro}".format(
- sys.implementation.version
- ),
- "os_name": os.name,
- "platform_machine": platform.machine(),
- "platform_release": platform.release(),
- "platform_system": platform.system(),
- "platform_version": platform.version(),
- "python_full_version": platform.python_version(),
- "platform_python_implementation": platform.python_implementation(),
- "python_version": ".".join(platform.python_version_tuple()[:2]),
- "sys_platform": sys.platform,
- }
-
- for p in pip_json["installed"]:
- meta = p["metadata"]
- name = meta["name"]
- key = normalize(name)
- requires = []
- if "requires_dist" in meta:
- for i in meta["requires_dist"]:
- det = (i + ";").split(";")
-
- # req_nameextra is "python-jose[cryptography]"
- # from fastapi "python-jose[cryptography]<4.0.0,>=3.3.0
- # req_nameextra is "google-cloud-storage"
- # from "google-cloud-storage (<2.0.0,>=1.26.0)
- req_nameextra = re.split(' |;|==|!|>|<', det[0]+ ";")[0]
- req_nameextra = normalize(req_nameextra)
- req_key = normalize((req_nameextra + "[").split("[")[0])
- req_key_extra = req_nameextra[len(req_key) + 1 :].split("]")[0]
- req_version = det[0][len(req_nameextra) :].translate(replacements)
- req_marker = det[1]
-
- req_add = {
- "req_key": req_key,
- "req_version": req_version,
- "req_extra": req_key_extra,
- }
- # add the marker of the requirement, if not nothing:
- if not req_marker == "":
- req_add["req_marker"] = req_marker
- requires += [req_add]
- self.distro[key] = {
- "name": name,
- "version": meta["version"],
- "summary": meta["summary"] if "summary" in meta else "",
- "requires_dist": requires,
- "wanted_per": [],
- "description": meta["description"] if "description" in meta else "",
- }
- # On a second pass, complement distro in reverse mode with 'wanted-per':
- # - get all downward links in 'requires_dist' of each package
- # - feed the required packages 'wanted_per' as a reverse dict of dict
- # contains =
- # req_key = upstream package_key
- # req_version = downstream package version wanted
- # req_marker = marker of the downstream package requirement (if any)
-
- for p in self.distro:
- for r in self.distro[p]["requires_dist"]:
- if r["req_key"] in self.distro:
- want_add = {
- "req_key": p,
- "req_version": r["req_version"],
- "req_extra": r["req_extra"],
- } # req_key_extra
- if "req_marker" in r:
- want_add["req_marker"] = r["req_marker"] # req_key_extra
- self.distro[r["req_key"]]["wanted_per"] += [want_add]
-
- def _downraw(self, pp, extra="", version_req="", depth=20, path=[]):
- """build a nested list of needed packages with given extra and depth"""
- envi = {"extra": extra, **self.environment}
- p = normalize(pp)
- ret_all = []
- if p in path:
- print("cycle!", "->".join(path + [p]))
- elif p in self.distro and len(path) <= depth:
- if extra == "":
- ret = [f'{p}=={self.distro[p]["version"]} {version_req}']
- else:
- ret = [f'{p}[{extra}]=={self.distro[p]["version"]} {version_req}']
- for r in self.distro[p]["requires_dist"]:
- if r["req_key"] in self.distro:
- if "req_marker" not in r or Marker(r["req_marker"]).evaluate(
- environment=envi
- ):
- ret += self._downraw(
- r["req_key"],
- r["req_extra"],
- r["req_version"],
- depth,
- path + [p],
- )
- ret_all += [ret]
- return ret_all
-
- def _upraw(self, pp, extra="", version_req="", depth=20, path=[]):
- """build a nested list of user packages with given extra and depth"""
- envi = {"extra": extra, **self.environment}
- p = normalize(pp)
- ret_all = []
- if p in path:
- print("cycle!", "->".join(path + [p]))
- elif p in self.distro and len(path) <= depth:
- if extra == "":
- ret_all = [f'{p}=={self.distro[p]["version"]} {version_req}']
- else:
- ret_all = [f'{p}[{extra}]=={self.distro[p]["version"]} {version_req}']
- ret = []
- for r in self.distro[p]["wanted_per"]:
- if r["req_key"] in self.distro and r["req_key"] not in path:
- if "req_marker" not in r or Marker(r["req_marker"]).evaluate(
- environment=envi
- ):
- ret += self._upraw(
- r["req_key"],
- "",
- f"[requires: {p}"
- + (
- "[" + r["req_extra"] + "]"
- if r["req_extra"] != ""
- else ""
- )
- + f'{r["req_version"]}]',
- depth,
- path + [p],
- )
- if not ret == []:
- ret_all += [ret]
- return ret_all
-
- def down(self, pp="", extra="", depth=99, indent=5, version_req=""):
- """print the downward requirements for the package or all packages"""
- if not pp == "":
- rawtext = json.dumps(
- self._downraw(pp, extra, version_req, depth), indent=indent
- )
- lines = [l for l in rawtext.split("\n") if len(l.strip()) > 2]
- print("\n".join(lines).replace('"', ""))
- else:
- for one_pp in sorted(self.distro):
- self.down(one_pp, extra, depth, indent, version_req)
-
- def up(self, pp, extra="", depth=99, indent=5, version_req=""):
- """print the upward needs for the package"""
- rawtext = json.dumps(self._upraw(pp, extra, version_req, depth), indent=indent)
- lines = [l for l in rawtext.split("\n") if len(l.strip()) > 2]
- print("\n".join(lines).replace('"', ""))
-
- def description(self, pp):
- "return desciption of the package"
- if pp in self.distro:
- return print("\n".join(self.distro[pp]["description"].split(r"\n")))
-
- def pip_list(self):
- """ do like pip list"""
- return [(p , self.distro[p]['version']) for p in sorted(self.distro)]
-
-
\ No newline at end of file
diff --git a/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0dotb3.toml b/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0dotb3.toml
new file mode 100644
index 00000000..e0aac7a6
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0dotb3.toml
@@ -0,0 +1,101 @@
+lock-version = "1.0"
+created-by = "pip"
+
+[[packages]]
+name = "build"
+version = "1.2.2.post1"
+
+[[packages.wheels]]
+name = "build-1.2.2.post1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"
+
+[[packages]]
+name = "colorama"
+version = "0.4.6"
+
+[[packages.wheels]]
+name = "colorama-0.4.6-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
+
+[[packages]]
+name = "packaging"
+version = "25.0"
+
+[[packages.wheels]]
+name = "packaging-25.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"
+
+[[packages]]
+name = "pyproject-hooks"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "pyproject_hooks-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"
+
+[[packages]]
+name = "setuptools"
+version = "80.9.0"
+
+[[packages.wheels]]
+name = "setuptools-80.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"
+
+[[packages]]
+name = "sqlite-bro"
+version = "0.13.1"
+
+[[packages.wheels]]
+name = "sqlite_bro-0.13.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/b3/81b91f5b26fff329c59dbf826a87637bd51d1903120427912322f86e7d33/sqlite_bro-0.13.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d"
+
+[[packages]]
+name = "sv-ttk"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "sv_ttk-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/3d/be0abc3202e90f282ad465f4e7c6e41bc8dce810ce5d1611566a1e7dfba8/sv_ttk-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"
+
+[[packages]]
+name = "wheel"
+version = "0.45.1"
+
+[[packages.wheels]]
+name = "wheel-0.45.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"
+
+[[packages]]
+name = "wppm"
+version = "17.2.20250823"
+
+[[packages.wheels]]
+name = "wppm-17.2.20250823-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ae/a9/2581cc7f91354eada41367bf68b91b1b7fba6cb6fb469f500dbaf6191539/wppm-17.2.20250823-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3"
diff --git a/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0slimb3.toml b/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0slimb3.toml
new file mode 100644
index 00000000..51734fb3
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0slimb3.toml
@@ -0,0 +1,5568 @@
+lock-version = "1.0"
+created-by = "pip"
+
+[[packages]]
+name = "absl-py"
+version = "2.3.0"
+
+[[packages.wheels]]
+name = "absl_py-2.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/04/9d75e1d3bb4ab8ec67ff10919476ccdee06c098bcfcf3a352da5f985171d/absl_py-2.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9824a48b654a306168f63e0d97714665f8490b8d89ec7bf2efc24bf67cf579b3"
+
+[[packages]]
+name = "adbc-driver-manager"
+version = "1.6.0"
+
+[[packages.wheels]]
+name = "adbc_driver_manager-1.6.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/bf/5f/a04791038cb659c8e1e7fb4a22d75a9fd3e3109a22822bd80beea0046dc4/adbc_driver_manager-1.6.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "0e8ffb182fafe1e6ae12964a833700daacc55f7abfdc2ada8b5214b18108d87b"
+
+[[packages]]
+name = "aiofiles"
+version = "24.1.0"
+
+[[packages.wheels]]
+name = "aiofiles-24.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"
+
+[[packages]]
+name = "aiohappyeyeballs"
+version = "2.6.1"
+
+[[packages.wheels]]
+name = "aiohappyeyeballs-2.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"
+
+[[packages]]
+name = "aiohttp"
+version = "3.11.18"
+
+[[packages.wheels]]
+name = "aiohttp-3.11.18-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/1e/3c/143831b32cd23b5263a995b2a1794e10aa42f8a895aae5074c20fda36c07/aiohttp-3.11.18-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01"
+
+[[packages]]
+name = "aiosignal"
+version = "1.3.2"
+
+[[packages.wheels]]
+name = "aiosignal-1.3.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"
+
+[[packages]]
+name = "aiosqlite"
+version = "0.21.0"
+
+[[packages.wheels]]
+name = "aiosqlite-0.21.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f5/10/6c25ed6de94c49f88a91fa5018cb4c0f3625f31d5be9f771ebe5cc7cd506/aiosqlite-0.21.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0"
+
+[[packages]]
+name = "alabaster"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "alabaster-1.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"
+
+[[packages]]
+name = "alembic"
+version = "1.16.1"
+
+[[packages.wheels]]
+name = "alembic-1.16.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/59/565286efff3692c5716c212202af61466480f6357c4ae3089d4453bff1f3/alembic-1.16.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0cdd48acada30d93aa1035767d67dff25702f8de74d7c3919f2e8492c8db2e67"
+
+[[packages]]
+name = "altair"
+version = "5.5.0"
+
+[[packages.wheels]]
+name = "altair-5.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/aa/f3/0b6ced594e51cc95d8c1fc1640d3623770d01e4969d29c0bd09945fafefa/altair-5.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c"
+
+[[packages]]
+name = "annotated-types"
+version = "0.7.0"
+
+[[packages.wheels]]
+name = "annotated_types-0.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"
+
+[[packages]]
+name = "ansicolors"
+version = "1.1.8"
+
+[[packages.wheels]]
+name = "ansicolors-1.1.8-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/53/18/a56e2fe47b259bb52201093a3a9d4a32014f9d85071ad07e9d60600890ca/ansicolors-1.1.8-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187"
+
+[[packages]]
+name = "anthropic"
+version = "0.64.0"
+
+[[packages.wheels]]
+name = "anthropic-0.64.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a9/b2/2d268bcd5d6441df9dc0ebebc67107657edb8b0150d3fda1a5b81d1bec45/anthropic-0.64.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6f5f7d913a6a95eb7f8e1bda4e75f76670e8acd8d4cd965e02e2a256b0429dd1"
+
+[[packages]]
+name = "anyio"
+version = "4.9.0"
+
+[[packages.wheels]]
+name = "anyio-4.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"
+
+[[packages]]
+name = "anywidget"
+version = "0.9.18"
+
+[[packages.wheels]]
+name = "anywidget-0.9.18-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2b/f0/09a30ca0551af20c7cefa7464b7ccb6f5407a550b83c4dcb15c410814849/anywidget-0.9.18-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "944b82ef1dd17b8ff0fb6d1f199f613caf9111338e6e2857da478f6e73770cb8"
+
+[[packages]]
+name = "appdirs"
+version = "1.4.4"
+
+[[packages.wheels]]
+name = "appdirs-1.4.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
+
+[[packages]]
+name = "argcomplete"
+version = "3.6.2"
+
+[[packages.wheels]]
+name = "argcomplete-3.6.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/da/e42d7a9d8dd33fa775f467e4028a47936da2f01e4b0e561f9ba0d74cb0ca/argcomplete-3.6.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "65b3133a29ad53fb42c48cf5114752c7ab66c1c38544fdf6460f450c09b42591"
+
+[[packages]]
+name = "argon2-cffi"
+version = "25.1.0"
+
+[[packages.wheels]]
+name = "argon2_cffi-25.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741"
+
+[[packages]]
+name = "argon2-cffi-bindings"
+version = "21.2.0"
+
+[[packages.wheels]]
+name = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"
+
+[[packages]]
+name = "array-api-compat"
+version = "1.12.0"
+
+[[packages.wheels]]
+name = "array_api_compat-1.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e0/b1/0542e0cab6f49f151a2d7a42400f84f706fc0b64e85dc1f56708b2e9fd37/array_api_compat-1.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0b4795b6944a9507fde54679f9350e2ad2b1e2acf4a2408a098cdc27f890a8b"
+
+[[packages]]
+name = "arrow"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "arrow-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"
+
+[[packages]]
+name = "asgi-csrf"
+version = "0.11"
+
+[[packages.wheels]]
+name = "asgi_csrf-0.11-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/1c/5d954baaf144852a4762368b37c06202b277378ea412acc5565f69acc9e9/asgi_csrf-0.11-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "03ac140115f39d4295288a9adf74fdc6ae607f6ef44abee8466520458207242b"
+
+[[packages]]
+name = "asgiref"
+version = "3.8.1"
+
+[[packages.wheels]]
+name = "asgiref-3.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"
+
+[[packages]]
+name = "asn1crypto"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "asn1crypto-1.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"
+
+[[packages]]
+name = "asteval"
+version = "1.0.5"
+
+[[packages.wheels]]
+name = "asteval-1.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0a/0d/2c6aaab67ac566d76322e87827d707214c5f6ffb5a4fcd456a8633da1788/asteval-1.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "082b95312578affc8a6d982f7d92b7ac5de05634985c87e7eedd3188d31149fa"
+
+[[packages]]
+name = "astroid"
+version = "3.3.9"
+
+[[packages.wheels]]
+name = "astroid-3.3.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/de/80/c749efbd8eef5ea77c7d6f1956e8fbfb51963b7f93ef79647afd4d9886e3/astroid-3.3.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d05bfd0acba96a7bd43e222828b7d9bc1e138aaeb0649707908d3702a9831248"
+
+[[packages]]
+name = "astropy"
+version = "7.1.0"
+
+[[packages.wheels]]
+name = "astropy-7.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/0b/dd/d9c55247172f7156696d85c9146b64b41c30405bf86b775a731bed4d52f8/astropy-7.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8e317f34e33a8f5517bc9fc6fbc005f42730d3be7d2820ef41e0468bcb796843"
+
+[[packages]]
+name = "astropy-iers-data"
+version = "0.2025.6.9.0.39.3"
+
+[[packages.wheels]]
+name = "astropy_iers_data-0.2025.6.9.0.39.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/39/18/83a74b38e1cfd2291f43daf0cf9ea59cd8dd8ded912c2e56141e6224d708/astropy_iers_data-0.2025.6.9.0.39.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "76855f5572707b8d25f77a0ede2b330b7ef9863bc963e3eda86321e4e32df802"
+
+[[packages]]
+name = "asttokens"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "asttokens-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"
+
+[[packages]]
+name = "async-lru"
+version = "2.0.5"
+
+[[packages.wheels]]
+name = "async_lru-2.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943"
+
+[[packages]]
+name = "asyncssh"
+version = "2.21.0"
+
+[[packages.wheels]]
+name = "asyncssh-2.21.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/99/56/db25216aa7f385ec71fdc489af80812171515cddbe68c0e515e98a291390/asyncssh-2.21.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cf7f3dfa52b2cb4ad31f0d77ff0d0a8fdd850203da84a0e72e62c36fdd4daf4b"
+
+[[packages]]
+name = "atomicwrites"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "atomicwrites-1.4.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/a0/da5f49008ec6e9a658dbf5d7310a4debd397bce0b4db03cf8a410066bb87/atomicwrites-1.4.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"
+
+[[packages]]
+name = "attrs"
+version = "25.3.0"
+
+[[packages.wheels]]
+name = "attrs-25.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"
+
+[[packages]]
+name = "autopep8"
+version = "2.0.4"
+
+[[packages.wheels]]
+name = "autopep8-2.0.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d8/f2/e63c9f9c485cd90df8e4e7ae90fa3be2469c9641888558c7b45fa98a76f8/autopep8-2.0.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb"
+
+[[packages]]
+name = "azure-core"
+version = "1.34.0"
+
+[[packages.wheels]]
+name = "azure_core-1.34.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/9e/5c87b49f65bb16571599bc789857d0ded2f53014d3392bc88a5d1f3ad779/azure_core-1.34.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0615d3b756beccdb6624d1c0ae97284f38b78fb59a2a9839bf927c66fbbdddd6"
+
+[[packages]]
+name = "azure-cosmos"
+version = "4.9.0"
+
+[[packages.wheels]]
+name = "azure_cosmos-4.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/dc/380f843744535497acd0b85aacb59565c84fc28bf938c8d6e897a858cd95/azure_cosmos-4.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3b60eaa01a16a857d0faf0cec304bac6fa8620a81bc268ce760339032ef617fe"
+
+[[packages]]
+name = "azure-identity"
+version = "1.23.0"
+
+[[packages.wheels]]
+name = "azure_identity-1.23.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/16/a51d47780f41e4b87bb2d454df6aea90a44a346e918ac189d3700f3d728d/azure_identity-1.23.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dbbeb64b8e5eaa81c44c565f264b519ff2de7ff0e02271c49f3cb492762a50b0"
+
+[[packages]]
+name = "babel"
+version = "2.17.0"
+
+[[packages.wheels]]
+name = "babel-2.17.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"
+
+[[packages]]
+name = "baresql"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "baresql-1.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d6/d2/fe24bcd99d97bddbbccdf191edf4e84c0fdfe894dfff9f54b05f36096ebb/baresql-1.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a24d17f46beb47c221f328f7e06710e3896c6203a8e1909788d7128f27b86f01"
+
+[[packages]]
+name = "bcrypt"
+version = "4.3.0"
+
+[[packages.wheels]]
+name = "bcrypt-4.3.0-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a9/cf/45fb5261ece3e6b9817d3d82b2f343a505fd58674a92577923bc500bd1aa/bcrypt-4.3.0-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b"
+
+[[packages]]
+name = "beautifulsoup4"
+version = "4.13.4"
+
+[[packages.wheels]]
+name = "beautifulsoup4-4.13.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b"
+
+[[packages]]
+name = "binaryornot"
+version = "0.4.4"
+
+[[packages.wheels]]
+name = "binaryornot-0.4.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"
+
+[[packages]]
+name = "black"
+version = "25.1.0"
+
+[[packages.wheels]]
+name = "black-25.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"
+
+[[packages]]
+name = "bleach"
+version = "6.2.0"
+
+[[packages.wheels]]
+name = "bleach-6.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"
+
+[[packages]]
+name = "blinker"
+version = "1.9.0"
+
+[[packages.wheels]]
+name = "blinker-1.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"
+
+[[packages]]
+name = "bokeh"
+version = "3.7.3"
+
+[[packages.wheels]]
+name = "bokeh-3.7.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/91/48/08b2382e739236aa3360b7976360ba3e0c043b6234e25951c18c1eb6fa06/bokeh-3.7.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b0e79dd737f088865212e4fdcb0f3b95d087f0f088bf8ca186a300ab1641e2c7"
+
+[[packages]]
+name = "branca"
+version = "0.8.1"
+
+[[packages.wheels]]
+name = "branca-0.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f8/9d/91cddd38bd00170aad1a4b198c47b4ed716be45c234e09b835af41f4e717/branca-0.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d29c5fab31f7c21a92e34bf3f854234e29fecdcf5d2df306b616f20d816be425"
+
+[[packages]]
+name = "brotli"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "Brotli-1.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7e/c1/ec214e9c94000d1c1974ec67ced1c970c148aa6b8d8373066123fc3dbf06/Brotli-1.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b"
+
+[[packages]]
+name = "build"
+version = "1.2.2.post1"
+
+[[packages.wheels]]
+name = "build-1.2.2.post1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"
+
+[[packages]]
+name = "cachetools"
+version = "5.5.2"
+
+[[packages.wheels]]
+name = "cachetools-5.5.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"
+
+[[packages]]
+name = "certifi"
+version = "2025.4.26"
+
+[[packages.wheels]]
+name = "certifi-2025.4.26-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"
+
+[[packages]]
+name = "cffi"
+version = "1.17.1"
+
+[[packages.wheels]]
+name = "cffi-1.17.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"
+
+[[packages]]
+name = "chardet"
+version = "5.2.0"
+
+[[packages.wheels]]
+name = "chardet-5.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"
+
+[[packages]]
+name = "charset-normalizer"
+version = "3.4.2"
+
+[[packages.wheels]]
+name = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"
+
+[[packages]]
+name = "clarabel"
+version = "0.10.0"
+
+[[packages.wheels]]
+name = "clarabel-0.10.0-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e6/ba/67a0defb70ed910877049e915e6738fc0432edd5e46b97743ce78a1e5b95/clarabel-0.10.0-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "7871b6f499ad66f71d4e7fb40754c4d986d4316f242beb62ff4f63a69785a50c"
+
+[[packages]]
+name = "click"
+version = "8.2.1"
+
+[[packages.wheels]]
+name = "click-8.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"
+
+[[packages]]
+name = "click-default-group"
+version = "1.2.4"
+
+[[packages.wheels]]
+name = "click_default_group-1.2.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/1a/aff8bb287a4b1400f69e09a53bd65de96aa5cee5691925b38731c67fc695/click_default_group-1.2.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f"
+
+[[packages]]
+name = "cloudpickle"
+version = "3.1.1"
+
+[[packages.wheels]]
+name = "cloudpickle-3.1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/e8/64c37fadfc2816a7701fa8a6ed8d87327c7d54eacfbfb6edab14a2f2be75/cloudpickle-3.1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c8c5a44295039331ee9dad40ba100a9c7297b6f988e50e87ccdf3765a668350e"
+
+[[packages]]
+name = "cohere"
+version = "5.16.1"
+
+[[packages.wheels]]
+name = "cohere-5.16.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/c6/72309ac75f3567425ca31a601ad394bfee8d0f4a1569dfbc80cbb2890d07/cohere-5.16.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "37e2c1d69b1804071b5e5f5cb44f8b74127e318376e234572d021a1a729c6baa"
+
+[[packages]]
+name = "colorama"
+version = "0.4.6"
+
+[[packages.wheels]]
+name = "colorama-0.4.6-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
+
+[[packages]]
+name = "colorcet"
+version = "3.1.0"
+
+[[packages.wheels]]
+name = "colorcet-3.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c6/c6/9963d588cc3d75d766c819e0377a168ef83cf3316a92769971527a1ad1de/colorcet-3.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2a7d59cc8d0f7938eeedd08aad3152b5319b4ba3bcb7a612398cc17a384cb296"
+
+[[packages]]
+name = "coloredlogs"
+version = "7.3.1"
+
+[[packages.wheels]]
+name = "coloredlogs-7.3.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/b3/3ea34a2248fa707d04900195589357ccb924ae8db8810ecf26e17c4cb2e3/coloredlogs-7.3.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f08ee2a2cef08163ddd24596e48cba2243937abf915d7fb37d62254596b816a9"
+
+[[packages]]
+name = "colorlog"
+version = "6.9.0"
+
+[[packages.wheels]]
+name = "colorlog-6.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e3/51/9b208e85196941db2f0654ad0357ca6388ab3ed67efdbfc799f35d1f83aa/colorlog-6.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff"
+
+[[packages]]
+name = "comm"
+version = "0.2.2"
+
+[[packages.wheels]]
+name = "comm-0.2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"
+
+[[packages]]
+name = "contourpy"
+version = "1.3.2"
+
+[[packages.wheels]]
+name = "contourpy-1.3.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9"
+
+[[packages]]
+name = "cookiecutter"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "cookiecutter-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d"
+
+[[packages]]
+name = "cryptography"
+version = "45.0.5"
+
+[[packages.wheels]]
+name = "cryptography-45.0.5-cp311-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/1f/10/197da38a5911a48dd5389c043de4aec4b3c94cb836299b01253940788d78/cryptography-45.0.5-cp311-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63"
+
+[[packages]]
+name = "cvxopt"
+version = "1.3.2"
+
+[[packages.wheels]]
+name = "cvxopt-1.3.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b9/55/90b40b489a235a9f35a532eb77cec81782e466779d9a531ffda6b2f99410/cvxopt-1.3.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "0a0987966009ad383de0918e61255d34ed9ebc783565bcb15470d4155010b6bf"
+
+[[packages]]
+name = "cvxpy"
+version = "1.6.5"
+
+[[packages.wheels]]
+name = "cvxpy-1.6.5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a0/3c/86682ec2b72f72e46e359903d7c18686e5314aa4baa96c77f6595c58fb03/cvxpy-1.6.5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "51161b0e8b0d83dc07355bab938bd0734dd5531c98dca8d6faaa8b847c651339"
+
+[[packages]]
+name = "cycler"
+version = "0.12.1"
+
+[[packages.wheels]]
+name = "cycler-0.12.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"
+
+[[packages]]
+name = "cython"
+version = "3.1.2"
+
+[[packages.wheels]]
+name = "cython-3.1.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c2/94/65ba40faeafe74845ba22b61aff7d73475671c3bd24bffc6cba53f3b0063/cython-3.1.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8ab1319c77f15b0ae04b3fb03588df3afdec4cf79e90eeea5c961e0ebd8fdf72"
+
+[[packages]]
+name = "cytoolz"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "cytoolz-1.0.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297"
+
+[[packages]]
+name = "dask"
+version = "2025.7.0"
+
+[[packages.wheels]]
+name = "dask-2025.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b3/f9/3e04725358c17329652da8c1b2dbd88de723f3dc78bf52ca6d28d52c9279/dask-2025.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "073c29c4e99c2400a39a8a67874f35c1d15bf7af9ae3d0c30af3c7c1199f24ae"
+
+[[packages]]
+name = "datasette"
+version = "0.65.1"
+
+[[packages.wheels]]
+name = "datasette-0.65.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/08/f7/fc15b9ddc7a2cafe546f0e2696d71940d7604a128e2f903e98238c3435f7/datasette-0.65.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ba7adf717ddcc24a2a8ac57890fffd384a2ebb909b342e4f731ba09eba764305"
+
+[[packages]]
+name = "datasette-graphql"
+version = "2.2"
+
+[[packages.wheels]]
+name = "datasette_graphql-2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f1/12/e8fb59d77c59ec47a2aa53a6d4ac57ad55fce2b48c8397c2866c3f2c66cd/datasette_graphql-2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cd9f61afdcaab1ce4ff6775296e6ece99305bf05cbfae4c1c938a6c9e60cd485"
+
+[[packages]]
+name = "datashader"
+version = "0.18.1"
+
+[[packages.wheels]]
+name = "datashader-0.18.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/05/3d/f783a19cedbd5e146543775404d6976ca2162fec53ccbba5ffd8da68bd9a/datashader-0.18.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5585af146e83af51c61d49168a741a6280a482072572e16573af1e5c6b600f8a"
+
+[[packages]]
+name = "deap"
+version = "1.4.2"
+
+[[packages.wheels]]
+name = "deap-1.4.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/6e/22/614264336b00b1a01447e31c941fd4576478b5d32184dbb552db27b1c2a1/deap-1.4.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "1abab976c75b0f18c36e81f968fcc77fac69fc9bedbab8be3323ca376f6fcfa4"
+
+[[packages]]
+name = "debugpy"
+version = "1.8.14"
+
+[[packages.wheels]]
+name = "debugpy-1.8.14-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e0/62/a7b4a57013eac4ccaef6977966e6bec5c63906dd25a86e35f155952e29a1/debugpy-1.8.14-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e"
+
+[[packages]]
+name = "decorator"
+version = "5.2.1"
+
+[[packages.wheels]]
+name = "decorator-5.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"
+
+[[packages]]
+name = "defusedxml"
+version = "0.7.1"
+
+[[packages.wheels]]
+name = "defusedxml-0.7.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
+
+[[packages]]
+name = "deprecated"
+version = "1.2.18"
+
+[[packages.wheels]]
+name = "Deprecated-1.2.18-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"
+
+[[packages]]
+name = "diff-match-patch"
+version = "20241021"
+
+[[packages.wheels]]
+name = "diff_match_patch-20241021-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f7/bb/2aa9b46a01197398b901e458974c20ed107935c26e44e37ad5b0e5511e44/diff_match_patch-20241021-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782"
+
+[[packages]]
+name = "dill"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "dill-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"
+
+[[packages]]
+name = "distributed"
+version = "2025.7.0"
+
+[[packages.wheels]]
+name = "distributed-2025.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/dc/9f033526ed98b65cda8adbd10b6eeeca0659203f67bd3e065ce172008887/distributed-2025.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "51b74526c2bee409ca968ee5532c79de1c1a1713664f5ccf90bdd81f17cfdc73"
+
+[[packages]]
+name = "distro"
+version = "1.9.0"
+
+[[packages.wheels]]
+name = "distro-1.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"
+
+[[packages]]
+name = "django"
+version = "5.2.1"
+
+[[packages.wheels]]
+name = "django-5.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/90/92/7448697b5838b3a1c6e1d2d6a673e908d0398e84dc4f803a2ce11e7ffc0f/django-5.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a9b680e84f9a0e71da83e399f1e922e1ab37b2173ced046b541c72e1589a5961"
+
+[[packages]]
+name = "dnspython"
+version = "2.7.0"
+
+[[packages.wheels]]
+name = "dnspython-2.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"
+
+[[packages]]
+name = "docstring-to-markdown"
+version = "0.17"
+
+[[packages.wheels]]
+name = "docstring_to_markdown-0.17-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/56/7b/af3d0da15bed3a8665419bb3a630585756920f4ad67abfdfef26240ebcc0/docstring_to_markdown-0.17-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fd7d5094aa83943bf5f9e1a13701866b7c452eac19765380dead666e36d3711c"
+
+[[packages]]
+name = "docutils"
+version = "0.21.2"
+
+[[packages.wheels]]
+name = "docutils-0.21.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"
+
+[[packages]]
+name = "duckdb"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "duckdb-1.3.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/ab/e9/f83285b0cb3729f24321a038f272490dfb76ca531b7cef832037b7bd077c/duckdb-1.3.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "fbdfc1c0b83b90f780ae74038187ee696bb56ab727a289752372d7ec42dda65b"
+
+[[packages]]
+name = "entrypoints"
+version = "0.4"
+
+[[packages.wheels]]
+name = "entrypoints-0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/35/a8/365059bbcd4572cbc41de17fd5b682be5868b218c3c5479071865cab9078/entrypoints-0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"
+
+[[packages]]
+name = "et-xmlfile"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "et_xmlfile-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"
+
+[[packages]]
+name = "eval-type-backport"
+version = "0.2.2"
+
+[[packages.wheels]]
+name = "eval_type_backport-0.2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a"
+
+[[packages]]
+name = "executing"
+version = "2.2.0"
+
+[[packages.wheels]]
+name = "executing-2.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"
+
+[[packages]]
+name = "faker"
+version = "37.3.0"
+
+[[packages.wheels]]
+name = "faker-37.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ce/99/045b2dae19a01b9fbb23b9971bc04f4ef808e7f3a213d08c81067304a210/faker-37.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "48c94daa16a432f2d2bc803c7ff602509699fca228d13e97e379cd860a7e216e"
+
+[[packages]]
+name = "fasta2a"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "fasta2a-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7a/df/dd967535662ecc9e101a7d6c0c643a055aabc3de47411c31c1dd624356c8/fasta2a-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8b855b36f29fde6dcb79ad55be337a8165381b679bec829913009c55581e284e"
+
+[[packages]]
+name = "fastapi"
+version = "0.115.12"
+
+[[packages.wheels]]
+name = "fastapi-0.115.12-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d"
+
+[[packages]]
+name = "fastavro"
+version = "1.11.1"
+
+[[packages.wheels]]
+name = "fastavro-1.11.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b8/51/38cbe243d5facccab40fc43a4c17db264c261be955ce003803d25f0da2c3/fastavro-1.11.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "cde7ed91b52ff21f0f9f157329760ba7251508ca3e9618af3ffdac986d9faaa2"
+
+[[packages]]
+name = "fastjsonschema"
+version = "2.21.1"
+
+[[packages.wheels]]
+name = "fastjsonschema-2.21.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"
+
+[[packages]]
+name = "filelock"
+version = "3.18.0"
+
+[[packages.wheels]]
+name = "filelock-3.18.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"
+
+[[packages]]
+name = "flake8"
+version = "7.1.1"
+
+[[packages.wheels]]
+name = "flake8-7.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d9/42/65004373ac4617464f35ed15931b30d764f53cdd30cc78d5aea349c8c050/flake8-7.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"
+
+[[packages]]
+name = "flask"
+version = "3.1.1"
+
+[[packages.wheels]]
+name = "flask-3.1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c"
+
+[[packages]]
+name = "flatbuffers"
+version = "25.2.10"
+
+[[packages.wheels]]
+name = "flatbuffers-25.2.10-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b8/25/155f9f080d5e4bc0082edfda032ea2bc2b8fab3f4d25d46c1e9dd22a1a89/flatbuffers-25.2.10-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ebba5f4d5ea615af3f7fd70fc310636fbb2bbd1f566ac0a23d98dd412de50051"
+
+[[packages]]
+name = "flexcache"
+version = "0.3"
+
+[[packages.wheels]]
+name = "flexcache-0.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32"
+
+[[packages]]
+name = "flexparser"
+version = "0.4"
+
+[[packages.wheels]]
+name = "flexparser-0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846"
+
+[[packages]]
+name = "flit"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "flit-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f5/82/ce1d3bb380b227e26e517655d1de7b32a72aad61fa21ff9bd91a2e2db6ee/flit-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2b4e7171dc22881fa6adc2dbf083e5ecc72520be3cd7587d2a803da94d6ef431"
+
+[[packages]]
+name = "flit-core"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "flit_core-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f2/65/b6ba90634c984a4fcc02c7e3afe523fef500c4980fec67cc27536ee50acf/flit_core-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e7a0304069ea895172e3c7bb703292e992c5d1555dd1233ab7b5621b5b69e62c"
+
+[[packages]]
+name = "folium"
+version = "0.19.5"
+
+[[packages.wheels]]
+name = "folium-0.19.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/81/4d/bcbee0676dc06f0b014a030cb928e158c96daafb872a01ddee7e60a8c998/folium-0.19.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4333fb3e6f3e9eedb231615d22c6d7df20aea5829554bd6908675865a37803b3"
+
+[[packages]]
+name = "fonttools"
+version = "4.58.5"
+
+[[packages.wheels]]
+name = "fonttools-4.58.5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/71/a3/21e921b16cb9c029d3308e0cb79c9a937e9ff1fc1ee28c2419f0957b9e7c/fonttools-4.58.5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bca61b14031a4b7dc87e14bf6ca34c275f8e4b9f7a37bc2fe746b532a924cf30"
+
+[[packages]]
+name = "fqdn"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "fqdn-1.5.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"
+
+[[packages]]
+name = "frozenlist"
+version = "1.7.0"
+
+[[packages.wheels]]
+name = "frozenlist-1.7.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba"
+
+[[packages]]
+name = "fsspec"
+version = "2025.5.1"
+
+[[packages.wheels]]
+name = "fsspec-2025.5.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bb/61/78c7b3851add1481b048b5fdc29067397a1784e2910592bc81bb3f608635/fsspec-2025.5.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462"
+
+[[packages]]
+name = "fuzzywuzzy"
+version = "0.18.0"
+
+[[packages.wheels]]
+name = "fuzzywuzzy-0.18.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/43/ff/74f23998ad2f93b945c0309f825be92e04e0348e062026998b5eefef4c33/fuzzywuzzy-0.18.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993"
+
+[[packages]]
+name = "geographiclib"
+version = "2.0"
+
+[[packages.wheels]]
+name = "geographiclib-2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/5a/a26132406f1f40cf51ea349a5f11b0a46cec02a2031ff82e391c2537247a/geographiclib-2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6b7225248e45ff7edcee32becc4e0a1504c606ac5ee163a5656d482e0cd38734"
+
+[[packages]]
+name = "geopandas"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "geopandas-1.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c4/64/7d344cfcef5efddf9cf32f59af7f855828e9d74b5f862eddf5bfd9f25323/geopandas-1.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "01e147d9420cc374d26f51fc23716ac307f32b49406e4bd8462c07e82ed1d3d6"
+
+[[packages]]
+name = "geopy"
+version = "2.4.1"
+
+[[packages.wheels]]
+name = "geopy-2.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e5/15/cf2a69ade4b194aa524ac75112d5caac37414b20a3a03e6865dfe0bd1539/geopy-2.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ae8b4bc5c1131820f4d75fce9d4aaaca0c85189b3aa5d64c3dcaf5e3b7b882a7"
+
+[[packages]]
+name = "gitdb"
+version = "4.0.12"
+
+[[packages.wheels]]
+name = "gitdb-4.0.12-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"
+
+[[packages]]
+name = "gitpython"
+version = "3.1.44"
+
+[[packages.wheels]]
+name = "GitPython-3.1.44-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110"
+
+[[packages]]
+name = "google-auth"
+version = "2.40.3"
+
+[[packages.wheels]]
+name = "google_auth-2.40.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca"
+
+[[packages]]
+name = "google-genai"
+version = "1.20.0"
+
+[[packages.wheels]]
+name = "google_genai-1.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b9/b4/08f3ea414060a7e7d4436c08bb22d03dabef74cc05ef13ef8cd846156d5b/google_genai-1.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ccd61d6ebcb14f5c778b817b8010e3955ae4f6ddfeaabf65f42f6d5e3e5a8125"
+
+[[packages]]
+name = "graphene"
+version = "3.4.3"
+
+[[packages.wheels]]
+name = "graphene-3.4.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71"
+
+[[packages]]
+name = "graphql-core"
+version = "3.2.6"
+
+[[packages.wheels]]
+name = "graphql_core-3.2.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ae/4f/7297663840621022bc73c22d7d9d80dbc78b4db6297f764b545cd5dd462d/graphql_core-3.2.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f"
+
+[[packages]]
+name = "graphql-relay"
+version = "3.2.0"
+
+[[packages.wheels]]
+name = "graphql_relay-3.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5"
+
+[[packages]]
+name = "greenlet"
+version = "3.2.3"
+
+[[packages.wheels]]
+name = "greenlet-3.2.3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/27/1a/199f9587e8cb08a0658f9c30f3799244307614148ffe8b1e3aa22f324dea/greenlet-3.2.3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3"
+
+[[packages]]
+name = "griffe"
+version = "1.7.3"
+
+[[packages.wheels]]
+name = "griffe-1.7.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/58/c6/5c20af38c2a57c15d87f7f38bee77d63c1d2a3689f74fefaf35915dd12b2/griffe-1.7.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75"
+
+[[packages]]
+name = "groq"
+version = "0.28.0"
+
+[[packages.wheels]]
+name = "groq-0.28.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ac/24/20fc18d1b3e0883aeb24286ca8f26dc1970561b07d9c4412c84561bdf307/groq-0.28.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c6f86638371c2cba2ca337232e76c8d412e75965ed7e3058d30c9aa5dfe84303"
+
+[[packages]]
+name = "guidata"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "guidata-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/85/d8/8ebcf690f4f7c828ac97630c48799fbde56847ece5ece7ab513532b3e221/guidata-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8cc05220126dfdd562281de9e761b0c279a4112d699bff55d4b17d95d7bfa1d1"
+
+[[packages]]
+name = "h11"
+version = "0.16.0"
+
+[[packages.wheels]]
+name = "h11-0.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"
+
+[[packages]]
+name = "h2"
+version = "4.2.0"
+
+[[packages.wheels]]
+name = "h2-4.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d0/9e/984486f2d0a0bd2b024bf4bc1c62688fcafa9e61991f041fb0e2def4a982/h2-4.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0"
+
+[[packages]]
+name = "h5py"
+version = "3.12.1"
+
+[[packages.wheels]]
+name = "h5py-3.12.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/50/51/0bbf3663062b2eeee78aa51da71e065f8a0a6e3cb950cc7020b4444999e6/h5py-3.12.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "52ab036c6c97055b85b2a242cb540ff9590bacfda0c03dd0cf0661b311f522f8"
+
+[[packages]]
+name = "hatchling"
+version = "1.27.0"
+
+[[packages.wheels]]
+name = "hatchling-1.27.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/08/e7/ae38d7a6dfba0533684e0b2136817d667588ae3ec984c1a4e5df5eb88482/hatchling-1.27.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d3a2f3567c4f926ea39849cdf924c7e99e6686c9c8e288ae1037c8fa2a5d937b"
+
+[[packages]]
+name = "holoviews"
+version = "1.20.2"
+
+[[packages.wheels]]
+name = "holoviews-1.20.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/df/67/066a1d984fa259ad7300084a70789579e104afd75fc58a1d44cda9c365d5/holoviews-1.20.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1f892c04bc23e8a3a9cde082b606b9463c9ff78c3d0c00e2ddcc41fe6e738458"
+
+[[packages]]
+name = "hpack"
+version = "4.1.0"
+
+[[packages.wheels]]
+name = "hpack-4.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496"
+
+[[packages]]
+name = "html5lib"
+version = "1.1"
+
+[[packages.wheels]]
+name = "html5lib-1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6c/dd/a834df6482147d48e225a49515aabc28974ad5a4ca3215c18a882565b028/html5lib-1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"
+
+[[packages]]
+name = "httpcore"
+version = "1.0.9"
+
+[[packages.wheels]]
+name = "httpcore-1.0.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"
+
+[[packages]]
+name = "httpie"
+version = "3.2.4"
+
+[[packages.wheels]]
+name = "httpie-3.2.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/03/b6/39bcf01e1185882f34bc9fb77d1fb4a27911a55f60ab407de34abc8a2347/httpie-3.2.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4bd0435cc4b9bca59501bc65089de96f3e93b393803f32a81951db62050ebf0b"
+
+[[packages]]
+name = "httpx"
+version = "0.28.1"
+
+[[packages.wheels]]
+name = "httpx-0.28.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"
+
+[[packages]]
+name = "httpx-sse"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "httpx_sse-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"
+
+[[packages]]
+name = "huggingface-hub"
+version = "0.34.4"
+
+[[packages.wheels]]
+name = "huggingface_hub-0.34.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a"
+
+[[packages]]
+name = "humanfriendly"
+version = "10.0"
+
+[[packages.wheels]]
+name = "humanfriendly-10.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"
+
+[[packages]]
+name = "hupper"
+version = "1.12.1"
+
+[[packages.wheels]]
+name = "hupper-1.12.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e872b959f09d90be5fb615bd2e62de89a0b57efc037bdf9637fb09cdf8552b19"
+
+[[packages]]
+name = "hvplot"
+version = "0.11.3"
+
+[[packages.wheels]]
+name = "hvplot-0.11.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ca/4a/3490c93a699f3d5e4d708748b494a44639dec973b609eb4e17c2d94bc733/hvplot-0.11.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5fa236a737ef3ca83870bf1b481218855834f4fad56ed0cb041ce5f2792cc7a3"
+
+[[packages]]
+name = "hypercorn"
+version = "0.17.3"
+
+[[packages.wheels]]
+name = "hypercorn-0.17.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0e/3b/dfa13a8d96aa24e40ea74a975a9906cfdc2ab2f4e3b498862a57052f04eb/hypercorn-0.17.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547"
+
+[[packages]]
+name = "hyperframe"
+version = "6.1.0"
+
+[[packages.wheels]]
+name = "hyperframe-6.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5"
+
+[[packages]]
+name = "hypothesis"
+version = "6.135.4"
+
+[[packages.wheels]]
+name = "hypothesis-6.135.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/d4/25b3a9f35199eb1904967ca3e6db4afd636911fa39695760b0afac84f38a/hypothesis-6.135.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6a3b13ce35d43e14aaf6a6ca4cc411e5342be5d05b77977499d07cf6a61e6e71"
+
+[[packages]]
+name = "id"
+version = "1.5.0"
+
+[[packages.wheels]]
+name = "id-1.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/cb/18326d2d89ad3b0dd143da971e77afd1e6ca6674f1b1c3df4b6bec6279fc/id-1.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"
+
+[[packages]]
+name = "idna"
+version = "3.10"
+
+[[packages.wheels]]
+name = "idna-3.10-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
+
+[[packages]]
+name = "imageio"
+version = "2.37.0"
+
+[[packages.wheels]]
+name = "imageio-2.37.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cb/bd/b394387b598ed84d8d0fa90611a90bee0adc2021820ad5729f7ced74a8e2/imageio-2.37.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed"
+
+[[packages]]
+name = "imagesize"
+version = "1.4.1"
+
+[[packages.wheels]]
+name = "imagesize-1.4.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"
+
+[[packages]]
+name = "importlib-metadata"
+version = "8.7.0"
+
+[[packages.wheels]]
+name = "importlib_metadata-8.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"
+
+[[packages]]
+name = "inflection"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "inflection-0.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
+
+[[packages]]
+name = "iniconfig"
+version = "2.1.0"
+
+[[packages.wheels]]
+name = "iniconfig-2.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"
+
+[[packages]]
+name = "intervaltree"
+version = "3.1.0"
+
+[packages.sdist]
+name = "intervaltree-3.1.0.tar.gz"
+url = "https://files.pythonhosted.org/packages/50/fb/396d568039d21344639db96d940d40eb62befe704ef849b27949ded5c3bb/intervaltree-3.1.0.tar.gz"
+
+[packages.sdist.hashes]
+sha256 = "902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d"
+
+[[packages]]
+name = "ipycanvas"
+version = "0.13.3"
+
+[[packages.wheels]]
+name = "ipycanvas-0.13.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/fc/e3867e413adbfede3a9c372ec015416ccb0a6493659db5812eeec447a73b/ipycanvas-0.13.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d37adb2f45d2fef1c3d33c69a0518055694d87827b2f577f3c426d7712f75daa"
+
+[[packages]]
+name = "ipykernel"
+version = "6.29.5"
+
+[[packages.wheels]]
+name = "ipykernel-6.29.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"
+
+[[packages]]
+name = "ipyleaflet"
+version = "0.20.0"
+
+[[packages.wheels]]
+name = "ipyleaflet-0.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/49/69/e9858f2c0b99bf9f036348d1c84b8026f438bb6875effe6a9bcd9883dada/ipyleaflet-0.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b4c20ddc0b17d68e226cd3367ca2215a4db7e2b14374468c0eeaa54b53e4d173"
+
+[[packages]]
+name = "ipympl"
+version = "0.9.7"
+
+[[packages.wheels]]
+name = "ipympl-0.9.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/86/6b/21c62f1b2b5e18c6553f7364487dfdf7eb7952b1000a1b7863c1f97819e9/ipympl-0.9.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3698ee7eaa0b047a7603517d7aa1b71b32118a5f51754cab45ec5d994f67208f"
+
+[[packages]]
+name = "ipython"
+version = "8.37.0"
+
+[[packages.wheels]]
+name = "ipython-8.37.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"
+
+[[packages]]
+name = "ipython-genutils"
+version = "0.2.0"
+
+[[packages.wheels]]
+name = "ipython_genutils-0.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fa/bc/9bd3b5c2b4774d5f33b2d544f1460be9df7df2fe42f352135381c347c69a/ipython_genutils-0.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"
+
+[[packages]]
+name = "ipython-sql"
+version = "0.5.0"
+
+[[packages.wheels]]
+name = "ipython_sql-0.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/30/8f/9e50fa53ffc371483f9d1b90c1175b706d28a2e978e90a8894035af01905/ipython_sql-0.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "61b46ecffb956f62dbc17b5744cf70c649104c8db9afd821aa39b31f7cbb5d5b"
+
+[[packages]]
+name = "ipywidgets"
+version = "8.1.7"
+
+[[packages.wheels]]
+name = "ipywidgets-8.1.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb"
+
+[[packages]]
+name = "isoduration"
+version = "20.11.0"
+
+[[packages.wheels]]
+name = "isoduration-20.11.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"
+
+[[packages]]
+name = "isort"
+version = "6.0.1"
+
+[[packages.wheels]]
+name = "isort-6.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"
+
+[[packages]]
+name = "itsdangerous"
+version = "2.2.0"
+
+[[packages.wheels]]
+name = "itsdangerous-2.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"
+
+[[packages]]
+name = "janus"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "janus-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/68/34/65604740edcb20e1bda6a890348ed7d282e7dd23aa00401cbe36fd0edbd9/janus-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7e6449d34eab04cd016befbd7d8c0d8acaaaab67cb59e076a69149f9031745f9"
+
+[[packages]]
+name = "jaraco-classes"
+version = "3.4.0"
+
+[[packages.wheels]]
+name = "jaraco.classes-3.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"
+
+[[packages]]
+name = "jaraco-context"
+version = "6.0.1"
+
+[[packages.wheels]]
+name = "jaraco.context-6.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"
+
+[[packages]]
+name = "jaraco-functools"
+version = "4.2.1"
+
+[[packages.wheels]]
+name = "jaraco_functools-4.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f3/fd/179a20f832824514df39a90bb0e5372b314fea99f217f5ab942b10a8a4e8/jaraco_functools-4.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e"
+
+[[packages]]
+name = "jedi"
+version = "0.19.2"
+
+[[packages.wheels]]
+name = "jedi-0.19.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"
+
+[[packages]]
+name = "jellyfish"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "jellyfish-1.2.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/40/aa/332fd282668a353570bdad56d65f526bc28ab73da1a3dd99e670af687186/jellyfish-1.2.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "c8089e918ddb1abae946e92d053f646a7f686d0d051ef69cdfaa28b37352bbdf"
+
+[[packages]]
+name = "jinja2"
+version = "3.1.6"
+
+[[packages.wheels]]
+name = "jinja2-3.1.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"
+
+[[packages]]
+name = "jiter"
+version = "0.10.0"
+
+[[packages.wheels]]
+name = "jiter-0.10.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7e/07/1c96b623128bcb913706e294adb5f768fb7baf8db5e1338ce7b4ee8c78ef/jiter-0.10.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "75f9eb72ecb640619c29bf714e78c9c46c9c4eaafd644bf78577ede459f330d4"
+
+[[packages]]
+name = "joblib"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "joblib-1.5.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a"
+
+[[packages]]
+name = "json5"
+version = "0.12.0"
+
+[[packages.wheels]]
+name = "json5-0.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db"
+
+[[packages]]
+name = "jsonpatch"
+version = "1.33"
+
+[[packages.wheels]]
+name = "jsonpatch-1.33-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"
+
+[[packages]]
+name = "jsonpointer"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "jsonpointer-3.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"
+
+[[packages]]
+name = "jsonschema"
+version = "4.24.0"
+
+[[packages.wheels]]
+name = "jsonschema-4.24.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d"
+
+[[packages]]
+name = "jsonschema-specifications"
+version = "2025.4.1"
+
+[[packages.wheels]]
+name = "jsonschema_specifications-2025.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"
+
+[[packages]]
+name = "julia"
+version = "0.6.2"
+
+[[packages.wheels]]
+name = "julia-0.6.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/af/2e9a1a996f32b34249582392bb419cf8983b627a1d31412acbe9d6dea5b0/julia-0.6.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "90752f71376fdb9919439d20496c2dab24486dfa4fe8a831d6dd14a1bcbc04d1"
+
+[[packages]]
+name = "jupyter"
+version = "1.1.1"
+
+[[packages.wheels]]
+name = "jupyter-1.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83"
+
+[[packages]]
+name = "jupyter-bokeh"
+version = "4.0.5"
+
+[[packages.wheels]]
+name = "jupyter_bokeh-4.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/47/78/33b2294aad62e5f95b89a89379c5995c2bd978018387ef8bec79f6dc272c/jupyter_bokeh-4.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1110076c14c779071cf492646a1a871aefa8a477261e4721327a666e65df1a2c"
+
+[[packages]]
+name = "jupyter-client"
+version = "8.6.3"
+
+[[packages.wheels]]
+name = "jupyter_client-8.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"
+
+[[packages]]
+name = "jupyter-console"
+version = "6.6.3"
+
+[[packages.wheels]]
+name = "jupyter_console-6.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485"
+
+[[packages]]
+name = "jupyter-core"
+version = "5.8.1"
+
+[[packages.wheels]]
+name = "jupyter_core-5.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0"
+
+[[packages]]
+name = "jupyter-events"
+version = "0.12.0"
+
+[[packages.wheels]]
+name = "jupyter_events-0.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb"
+
+[[packages]]
+name = "jupyter-leaflet"
+version = "0.20.0"
+
+[[packages.wheels]]
+name = "jupyter_leaflet-0.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/16/95/ffe543060eb3b1570d78c3f2c1948c640a6758ff5c6479c27e474819115b/jupyter_leaflet-0.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2e27ce83647316424f04845e3a6af35e1ee44c177c318a145646b11f4afe0764"
+
+[[packages]]
+name = "jupyter-lsp"
+version = "2.2.5"
+
+[[packages.wheels]]
+name = "jupyter_lsp-2.2.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da"
+
+[[packages]]
+name = "jupyter-server"
+version = "2.16.0"
+
+[[packages.wheels]]
+name = "jupyter_server-2.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/46/1f/5ebbced977171d09a7b0c08a285ff9a20aafb9c51bde07e52349ff1ddd71/jupyter_server-2.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3d8db5be3bc64403b1c65b400a1d7f4647a5ce743f3b20dbdefe8ddb7b55af9e"
+
+[[packages]]
+name = "jupyter-server-terminals"
+version = "0.5.3"
+
+[[packages.wheels]]
+name = "jupyter_server_terminals-0.5.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"
+
+[[packages]]
+name = "jupyterlab"
+version = "4.4.4"
+
+[[packages.wheels]]
+name = "jupyterlab-4.4.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f8/82/66910ce0995dbfdb33609f41c99fe32ce483b9624a3e7d672af14ff63b9f/jupyterlab-4.4.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd"
+
+[[packages]]
+name = "jupyterlab-pygments"
+version = "0.3.0"
+
+[[packages.wheels]]
+name = "jupyterlab_pygments-0.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"
+
+[[packages]]
+name = "jupyterlab-server"
+version = "2.27.3"
+
+[[packages.wheels]]
+name = "jupyterlab_server-2.27.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4"
+
+[[packages]]
+name = "jupyterlab-widgets"
+version = "3.0.15"
+
+[[packages.wheels]]
+name = "jupyterlab_widgets-3.0.15-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c"
+
+[[packages]]
+name = "keras"
+version = "3.11.3"
+
+[[packages.wheels]]
+name = "keras-3.11.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/94/5b/4c778cc921ce4b864b238f63f8e3ff6e954ab19b80c9fa680593ad8093d4/keras-3.11.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f484f050e05ee400455b05ec8c36ed35edc34de94256b6073f56cfe68f65491f"
+
+[[packages]]
+name = "keyring"
+version = "25.6.0"
+
+[[packages.wheels]]
+name = "keyring-25.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"
+
+[[packages]]
+name = "kiwisolver"
+version = "1.4.8"
+
+[[packages.wheels]]
+name = "kiwisolver-1.4.8-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2"
+
+[[packages]]
+name = "langchain"
+version = "0.3.27"
+
+[[packages.wheels]]
+name = "langchain-0.3.27-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f6/d5/4861816a95b2f6993f1360cfb605aacb015506ee2090433a71de9cca8477/langchain-0.3.27-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7b20c4f338826acb148d885b20a73a16e410ede9ee4f19bb02011852d5f98798"
+
+[[packages]]
+name = "langchain-core"
+version = "0.3.72"
+
+[[packages.wheels]]
+name = "langchain_core-0.3.72-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6e/7d/9f75023c478e3b854d67da31d721e39f0eb30ae969ec6e755430cb1c0fb5/langchain_core-0.3.72-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9fa15d390600eb6b6544397a7aa84be9564939b6adf7a2b091179ea30405b240"
+
+[[packages]]
+name = "langchain-text-splitters"
+version = "0.3.9"
+
+[[packages.wheels]]
+name = "langchain_text_splitters-0.3.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/52/7638394b88bc15083fd2c3752a843784d9d2d110d68fed6437c8607fb749/langchain_text_splitters-0.3.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cee0bb816211584ea79cc79927317c358543f40404bcfdd69e69ba3ccde54401"
+
+[[packages]]
+name = "langsmith"
+version = "0.4.8"
+
+[[packages.wheels]]
+name = "langsmith-0.4.8-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/19/4f/481324462c44ce21443b833ad73ee51117031d41c16fec06cddbb7495b26/langsmith-0.4.8-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ca2f6024ab9d2cd4d091b2e5b58a5d2cb0c354a0c84fe214145a89ad450abae0"
+
+[[packages]]
+name = "lazy-loader"
+version = "0.4"
+
+[[packages.wheels]]
+name = "lazy_loader-0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc"
+
+[[packages]]
+name = "linkify-it-py"
+version = "2.0.3"
+
+[[packages.wheels]]
+name = "linkify_it_py-2.0.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79"
+
+[[packages]]
+name = "llvmlite"
+version = "0.44.0"
+
+[[packages.wheels]]
+name = "llvmlite-0.44.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/d0/81/e66fc86539293282fd9cb7c9417438e897f369e79ffb62e1ae5e5154d4dd/llvmlite-0.44.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "2fb7c4f2fb86cbae6dca3db9ab203eeea0e22d73b99bc2341cdf9de93612e930"
+
+[[packages]]
+name = "lmfit"
+version = "1.3.3"
+
+[[packages.wheels]]
+name = "lmfit-1.3.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6a/e1/d5aeb89530550c7e797d3528225fa31012490e79c9df5cf72a0f07cc66d3/lmfit-1.3.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a9e9ec7d0d0ec962cc6c078ad1ec6c8311d3ac0e5f0947a00a91f5509dacc2b2"
+
+[[packages]]
+name = "locket"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "locket-1.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b6c819a722f7b6bd955b80781788e4a66a55628b858d347536b7e81325a3a5e3"
+
+[[packages]]
+name = "logfire-api"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "logfire_api-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/97/c6/210bb1da7119af155276046c18ceff29867dfe9ea4bcb7d03397b28bd1cd/logfire_api-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fc092c2dcb24c8462ba776f3b0c2183f82e1cd55f86e29b38cf21a048e66a17d"
+
+[[packages]]
+name = "lxml"
+version = "6.0.0"
+
+[[packages.wheels]]
+name = "lxml-6.0.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f4/87/6456b9541d186ee7d4cb53bf1b9a0d7f3b1068532676940fdd594ac90865/lxml-6.0.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e"
+
+[[packages]]
+name = "magika"
+version = "0.6.2"
+
+[[packages.wheels]]
+name = "magika-0.6.2-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b0/1f/28e412d0ccedc068fbccdae6a6233faaa97ec3e5e2ffd242e49655b10064/magika-0.6.2-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "711f427a633e0182737dcc2074748004842f870643585813503ff2553b973b9f"
+
+[[packages]]
+name = "mako"
+version = "1.3.10"
+
+[[packages.wheels]]
+name = "mako-1.3.10-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"
+
+[[packages]]
+name = "markdown"
+version = "3.7"
+
+[[packages.wheels]]
+name = "Markdown-3.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"
+
+[[packages]]
+name = "markdown-it-py"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "markdown_it_py-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"
+
+[[packages]]
+name = "markdownify"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "markdownify-1.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/64/11/b751af7ad41b254a802cf52f7bc1fca7cabe2388132f2ce60a1a6b9b9622/markdownify-1.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "32a5a08e9af02c8a6528942224c91b933b4bd2c7d078f9012943776fc313eeef"
+
+[[packages]]
+name = "markitdown"
+version = "0.1.2"
+
+[[packages.wheels]]
+name = "markitdown-0.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ed/33/d52d06b44c28e0db5c458690a4356e6abbb866f4abc00c0cf4eebb90ca78/markitdown-0.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4881f0768794ffccb52d09dd86498813a6896ba9639b4fc15512817f56ed9d74"
+
+[[packages]]
+name = "markupsafe"
+version = "3.0.2"
+
+[[packages.wheels]]
+name = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"
+
+[[packages]]
+name = "matplotlib"
+version = "3.10.5"
+
+[[packages.wheels]]
+name = "matplotlib-3.10.5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/36/c2/24302e93ff431b8f4173ee1dd88976c8d80483cadbc5d3d777cef47b3a1c/matplotlib-3.10.5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "07442d2692c9bd1cceaa4afb4bbe5b57b98a7599de4dabfcca92d3eea70f9ebe"
+
+[[packages]]
+name = "matplotlib-inline"
+version = "0.1.7"
+
+[[packages.wheels]]
+name = "matplotlib_inline-0.1.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"
+
+[[packages]]
+name = "maturin"
+version = "1.9.0"
+
+[[packages.wheels]]
+name = "maturin-1.9.0-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/0e/44/b3236b2a3f6d26600cb3c81535c06c80fd80cbcdcf893648d8bb8660edbe/maturin-1.9.0-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "fb9796c1893d1e3cd9da9325ef3c63d54a5b0fe6183ddae4954b10c64a1ae5e3"
+
+[[packages]]
+name = "mccabe"
+version = "0.7.0"
+
+[[packages.wheels]]
+name = "mccabe-0.7.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
+
+[[packages]]
+name = "mcp"
+version = "1.9.3"
+
+[[packages.wheels]]
+name = "mcp-1.9.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/79/45/823ad05504bea55cb0feb7470387f151252127ad5c72f8882e8fe6cf5c0e/mcp-1.9.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "69b0136d1ac9927402ed4cf221d4b8ff875e7132b0b06edd446448766f34f9b9"
+
+[[packages]]
+name = "mdit-py-plugins"
+version = "0.4.2"
+
+[[packages.wheels]]
+name = "mdit_py_plugins-0.4.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"
+
+[[packages]]
+name = "mdurl"
+version = "0.1.2"
+
+[[packages.wheels]]
+name = "mdurl-0.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"
+
+[[packages]]
+name = "mercantile"
+version = "1.2.1"
+
+[[packages.wheels]]
+name = "mercantile-1.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b2/d6/de0cc74f8d36976aeca0dd2e9cbf711882ff8e177495115fd82459afdc4d/mercantile-1.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "30f457a73ee88261aab787b7069d85961a5703bb09dc57a170190bc042cd023f"
+
+[[packages]]
+name = "mergedeep"
+version = "1.3.4"
+
+[[packages.wheels]]
+name = "mergedeep-1.3.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"
+
+[[packages]]
+name = "missingno"
+version = "0.5.2"
+
+[[packages.wheels]]
+name = "missingno-0.5.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/22/cd5cf999af21c2f97486622c551ac3d07361ced8125121e907f588ff5f24/missingno-0.5.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "55782621ce09ba0f0a1d08e5bd6d6fe1946469fb03951fadf7d209911ca5b072"
+
+[[packages]]
+name = "mistralai"
+version = "1.9.3"
+
+[[packages.wheels]]
+name = "mistralai-1.9.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/9a/0c48706c646b0391b798f8568f2b1545e54d345805e988003c10450b7b4c/mistralai-1.9.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "962445e7cebadcbfbcd1daf973e853a832dcf7aba6320468fcf7e2cf5f943aec"
+
+[[packages]]
+name = "mistune"
+version = "3.1.3"
+
+[[packages.wheels]]
+name = "mistune-3.1.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/01/4d/23c4e4f09da849e127e9f123241946c23c1e30f45a88366879e064211815/mistune-3.1.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9"
+
+[[packages]]
+name = "mizani"
+version = "0.11.4"
+
+[[packages.wheels]]
+name = "mizani-0.11.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/11/f3777ad46c5d92e3ead121c22ea45fafb6c3b2c1edca0c0c6494969c125c/mizani-0.11.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5b6271dc3da2c88694dca2e0e0a7e1879f0e2fb046c789776f54d090a5243735"
+
+[[packages]]
+name = "ml-dtypes"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "ml_dtypes-0.5.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/da/8a/a2b9375c94077e5a488a624a195621407846f504068ce22ccf805c674156/ml_dtypes-0.5.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "fd918d4e6a4e0c110e2e05be7a7814d10dc1b95872accbf6512b80a109b71ae1"
+
+[[packages]]
+name = "mlxtend"
+version = "0.23.3"
+
+[[packages.wheels]]
+name = "mlxtend-0.23.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/92/5c322336a0991949a1e91f6acd7e04f7e05b0fb6252a3f00fcdc0cb5e97d/mlxtend-0.23.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f9fec721c4121be87dac00e513456dde5bf56b7427750719c0a291cd58b6538e"
+
+[[packages]]
+name = "more-itertools"
+version = "10.7.0"
+
+[[packages.wheels]]
+name = "more_itertools-10.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e"
+
+[[packages]]
+name = "mpld3"
+version = "0.5.10"
+
+[[packages.wheels]]
+name = "mpld3-0.5.10-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/95/6a/e3691bcc47485f38b09853207c928130571821d187cf174eed5418d45e82/mpld3-0.5.10-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1"
+
+[[packages]]
+name = "mpmath"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "mpmath-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"
+
+[[packages]]
+name = "msal"
+version = "1.32.3"
+
+[[packages.wheels]]
+name = "msal-1.32.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/bf/81516b9aac7fd867709984d08eb4db1d2e3fe1df795c8e442cde9b568962/msal-1.32.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b2798db57760b1961b142f027ffb7c8169536bf77316e99a0df5c4aaebb11569"
+
+[[packages]]
+name = "msal-extensions"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "msal_extensions-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5e/75/bd9b7bb966668920f06b200e84454c8f3566b102183bc55c5473d96cb2b9/msal_extensions-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca"
+
+[[packages]]
+name = "msgpack"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "msgpack-1.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b6/bc/8bd826dd03e022153bfa1766dcdec4976d6c818865ed54223d71f07862b3/msgpack-1.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"
+
+[[packages]]
+name = "multidict"
+version = "6.4.4"
+
+[[packages.wheels]]
+name = "multidict-6.4.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373"
+
+[[packages]]
+name = "multipledispatch"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "multipledispatch-1.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/51/c0/00c9809d8b9346eb238a6bbd5f83e846a4ce4503da94a4c08cb7284c325b/multipledispatch-1.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0c53cd8b077546da4e48869f49b13164bebafd0c2a5afceb6bb6a316e7fb46e4"
+
+[[packages]]
+name = "mypy"
+version = "1.16.1"
+
+[[packages.wheels]]
+name = "mypy-1.16.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/5a/fd/d486a0827a1c597b3b48b1bdef47228a6e9ee8102ab8c28f944cb83b65dc/mypy-1.16.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee"
+
+[[packages]]
+name = "mypy-extensions"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "mypy_extensions-1.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"
+
+[[packages]]
+name = "mysql-connector-python"
+version = "9.2.0"
+
+[[packages.wheels]]
+name = "mysql_connector_python-9.2.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/22/4b/4f5462a81d046bb54bbb62ffbcea654e78f3ae2a64eb24a14c2872c4d75e/mysql_connector_python-9.2.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "6557942f6c6be3b41d2965456b53a244a7ce3e6fb81cb195c243549be72a6a24"
+
+[[packages]]
+name = "namex"
+version = "0.1.0"
+
+[[packages.wheels]]
+name = "namex-0.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b2/bc/465daf1de06409cdd4532082806770ee0d8d7df434da79c76564d0f69741/namex-0.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e2012a474502f1e2251267062aae3114611f07df4224b6e06334c57b0f2ce87c"
+
+[[packages]]
+name = "narwhals"
+version = "2.0.1"
+
+[[packages.wheels]]
+name = "narwhals-2.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/26/43caf834e47c63883a5eddc02893b7fdbe6a0a4508ff6dc401907f3cc085/narwhals-2.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "837457e36a2ba1710c881fb69e1f79ce44fb81728c92ac378f70892a53af8ddb"
+
+[[packages]]
+name = "nbclient"
+version = "0.10.2"
+
+[[packages.wheels]]
+name = "nbclient-0.10.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d"
+
+[[packages]]
+name = "nbconvert"
+version = "7.16.6"
+
+[[packages.wheels]]
+name = "nbconvert-7.16.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b"
+
+[[packages]]
+name = "nbformat"
+version = "5.10.4"
+
+[[packages.wheels]]
+name = "nbformat-5.10.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"
+
+[[packages]]
+name = "nest-asyncio"
+version = "1.6.0"
+
+[[packages.wheels]]
+name = "nest_asyncio-1.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"
+
+[[packages]]
+name = "networkx"
+version = "3.5"
+
+[[packages.wheels]]
+name = "networkx-3.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec"
+
+[[packages]]
+name = "nh3"
+version = "0.2.21"
+
+[[packages.wheels]]
+name = "nh3-0.2.21-cp38-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/23/fc/8ce756c032c70ae3dd1d48a3552577a325475af2a2f629604b44f571165c/nh3-0.2.21-cp38-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629"
+
+[[packages]]
+name = "nltk"
+version = "3.9.1"
+
+[[packages.wheels]]
+name = "nltk-3.9.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4d/66/7d9e26593edda06e8cb531874633f7c2372279c3b0f46235539fe546df8b/nltk-3.9.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1"
+
+[[packages]]
+name = "notebook"
+version = "7.4.2"
+
+[[packages.wheels]]
+name = "notebook-7.4.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/1e/16/d3c36a0b1f6dfcf218add8eaf803bf0473ff50681ac4d51acb7ba02bce34/notebook-7.4.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9ccef602721aaa5530852e3064710b8ae5415c4e2ce26f8896d0433222755259"
+
+[[packages]]
+name = "notebook-shim"
+version = "0.2.4"
+
+[[packages.wheels]]
+name = "notebook_shim-0.2.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef"
+
+[[packages]]
+name = "numba"
+version = "0.61.2"
+
+[[packages.wheels]]
+name = "numba-0.61.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/af/a4/6d3a0f2d3989e62a18749e1e9913d5fa4910bbb3e3311a035baea6caf26d/numba-0.61.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "59321215e2e0ac5fa928a8020ab00b8e57cda8a97384963ac0dfa4d4e6aa54e7"
+
+[[packages]]
+name = "numpy"
+version = "2.2.6"
+
+[[packages.wheels]]
+name = "numpy-2.2.6-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"
+
+[[packages]]
+name = "numpydoc"
+version = "1.8.0"
+
+[[packages.wheels]]
+name = "numpydoc-1.8.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6c/45/56d99ba9366476cd8548527667f01869279cedb9e66b28eb4dfb27701679/numpydoc-1.8.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72024c7fd5e17375dec3608a27c03303e8ad00c81292667955c6fea7a3ccf541"
+
+[[packages]]
+name = "onnxruntime"
+version = "1.22.1"
+
+[[packages.wheels]]
+name = "onnxruntime-1.22.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/4c/06/9c765e66ad32a7e709ce4cb6b95d7eaa9cb4d92a6e11ea97c20ffecaf765/onnxruntime-1.22.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "70980d729145a36a05f74b573435531f55ef9503bcda81fc6c3d6b9306199982"
+
+[[packages]]
+name = "openai"
+version = "1.101.0"
+
+[[packages.wheels]]
+name = "openai-1.101.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c8/a6/0e39baa335bbd1c66c7e0a41dbbec10c5a15ab95c1344e7f7beb28eee65a/openai-1.101.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6539a446cce154f8d9fb42757acdfd3ed9357ab0d34fcac11096c461da87133b"
+
+[[packages]]
+name = "opencv-python"
+version = "4.11.0.86"
+
+[[packages.wheels]]
+name = "opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a4/7d/f1c30a92854540bf789e9cd5dde7ef49bbe63f855b85a2e6b3db8135c591/opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec"
+
+[[packages]]
+name = "openpyxl"
+version = "3.1.5"
+
+[[packages.wheels]]
+name = "openpyxl-3.1.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"
+
+[[packages]]
+name = "opentelemetry-api"
+version = "1.34.1"
+
+[[packages.wheels]]
+name = "opentelemetry_api-1.34.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/3a/2ba85557e8dc024c0842ad22c570418dc02c36cbd1ab4b832a93edf071b8/opentelemetry_api-1.34.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c"
+
+[[packages]]
+name = "optree"
+version = "0.14.1"
+
+[[packages.wheels]]
+name = "optree-0.14.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/90/43/93aa65f56b857b8364e76d76eb188a4a6912ed305374b90f9ba30dcf0de9/optree-0.14.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "25ea23fc6d6c0fa7dcf85afcfe10b43ed4fdf0e9d958a3677cd27fcdf0ca17d6"
+
+[[packages]]
+name = "optuna"
+version = "4.2.1"
+
+[[packages.wheels]]
+name = "optuna-4.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/28/09/c4d329f7969443cdd4d482048ca406b6f61cda3c8e99ace71feaec7c8734/optuna-4.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6d38199013441d3f70fac27136e05c0188c5f4ec3848db708ac311cbdeb30dbf"
+
+[[packages]]
+name = "orjson"
+version = "3.10.18"
+
+[[packages.wheels]]
+name = "orjson-3.10.18-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/4b/03/c75c6ad46be41c16f4cfe0352a2d1450546f3c09ad2c9d341110cd87b025/orjson-3.10.18-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52"
+
+[[packages]]
+name = "osqp"
+version = "0.6.7.post3"
+
+[[packages.wheels]]
+name = "osqp-0.6.7.post3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/4b/0a/acd48ad432ccf2538972805095108801a3b29a2433b48bd3a34e640df1e4/osqp-0.6.7.post3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "acb219e941f5248da5de3ee9b70e6a5aaddf5f3989dffd1d4c03b0f7b1dfa17b"
+
+[[packages]]
+name = "outcome"
+version = "1.3.0.post0"
+
+[[packages.wheels]]
+name = "outcome-1.3.0.post0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b"
+
+[[packages]]
+name = "overrides"
+version = "7.7.0"
+
+[[packages.wheels]]
+name = "overrides-7.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49"
+
+[[packages]]
+name = "packaging"
+version = "25.0"
+
+[[packages.wheels]]
+name = "packaging-25.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"
+
+[[packages]]
+name = "pandas"
+version = "2.3.1"
+
+[[packages.wheels]]
+name = "pandas-2.3.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b2/c0/54415af59db5cdd86a3d3bf79863e8cc3fa9ed265f0745254061ac09d5f2/pandas-2.3.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956"
+
+[[packages]]
+name = "pandocfilters"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "pandocfilters-1.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"
+
+[[packages]]
+name = "panel"
+version = "1.6.3"
+
+[[packages.wheels]]
+name = "panel-1.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7a/fe/d01b6eae59933d56c345e57cdde5ffe379b7b1f56d192782ab8071249f73/panel-1.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ccd2a0587ab382bd55b8ea099706f31b64aadac697b8a41923d3b18b9ed618d6"
+
+[[packages]]
+name = "papermill"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "papermill-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/55/83ce641bc61a70cc0721af6f50154ecaaccedfbdbc27366c1755a2a34972/papermill-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0f09da6ef709f3f14dde77cb1af052d05b14019189869affff374c9e612f2dd5"
+
+[[packages]]
+name = "param"
+version = "2.2.0"
+
+[[packages.wheels]]
+name = "param-2.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/99/56/370a6636e072a037b52499edd8928942df7f887974fc54444ece5152d26a/param-2.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "777f8c7b66ab820b70ea5ad09faaa6818308220caae89da3b5c5f359faa72a5e"
+
+[[packages]]
+name = "parso"
+version = "0.8.4"
+
+[[packages.wheels]]
+name = "parso-0.8.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"
+
+[[packages]]
+name = "partd"
+version = "1.4.2"
+
+[[packages.wheels]]
+name = "partd-1.4.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "978e4ac767ec4ba5b86c6eaa52e5a2a3bc748a2ca839e8cc798f1cc6ce6efb0f"
+
+[[packages]]
+name = "pathspec"
+version = "0.12.1"
+
+[[packages.wheels]]
+name = "pathspec-0.12.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"
+
+[[packages]]
+name = "patsy"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "patsy-1.0.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/2b/b50d3d08ea0fc419c183a84210571eba005328efa62b6b98bc28e9ead32a/patsy-1.0.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "751fb38f9e97e62312e921a1954b81e1bb2bcda4f5eeabaf94db251ee791509c"
+
+[[packages]]
+name = "pep8"
+version = "1.7.1"
+
+[[packages.wheels]]
+name = "pep8-1.7.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/42/3f/669429ce58de2c22d8d2c542752e137ec4b9885fff398d3eceb1a7f5acb4/pep8-1.7.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee"
+
+[[packages]]
+name = "pexpect"
+version = "4.9.0"
+
+[[packages.wheels]]
+name = "pexpect-4.9.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"
+
+[[packages]]
+name = "pg8000"
+version = "1.31.2"
+
+[[packages.wheels]]
+name = "pg8000-1.31.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/09/a0/2b30d52017c4ced8fc107386666ea7573954eb708bf66121f0229df05d41/pg8000-1.31.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "436c771ede71af4d4c22ba867a30add0bc5c942d7ab27fadbb6934a487ecc8f6"
+
+[[packages]]
+name = "pickleshare"
+version = "0.7.5"
+
+[[packages.wheels]]
+name = "pickleshare-0.7.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9a/41/220f49aaea88bc6fa6cba8d05ecf24676326156c23b991e80b3f2fc24c77/pickleshare-0.7.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"
+
+[[packages]]
+name = "pillow"
+version = "11.3.0"
+
+[[packages.wheels]]
+name = "pillow-11.3.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"
+
+[[packages]]
+name = "platformdirs"
+version = "4.3.7"
+
+[[packages.wheels]]
+name = "platformdirs-4.3.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6d/45/59578566b3275b8fd9157885918fcd0c4d74162928a5310926887b856a51/platformdirs-4.3.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"
+
+[[packages]]
+name = "plotly"
+version = "6.2.0"
+
+[[packages.wheels]]
+name = "plotly-6.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ed/20/f2b7ac96a91cc5f70d81320adad24cc41bf52013508d649b1481db225780/plotly-6.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "32c444d4c940887219cb80738317040363deefdfee4f354498cc0b6dab8978bd"
+
+[[packages]]
+name = "plotnine"
+version = "0.13.6"
+
+[[packages.wheels]]
+name = "plotnine-0.13.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/93/b1/e1c84e68cf24e83c4d251122e04c48840be203dafb4727e738381cdefa74/plotnine-0.13.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4acc1af29fa4e91e726b67d49277e8368f62e1c817f01bf14ecd8ca5e83bfaea"
+
+[[packages]]
+name = "plotpy"
+version = "2.7.4"
+
+[[packages.wheels]]
+name = "plotpy-2.7.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/61/98/9bc8f5a00dd45b53c37292c08ebcf9f94e895838ab2ad295d1c0eec88332/plotpy-2.7.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8dff5fd388048a8d3b4251329a9fe4027920386e0ebcc3c3642f59c432118c29"
+
+[[packages]]
+name = "pluggy"
+version = "1.5.0"
+
+[[packages.wheels]]
+name = "pluggy-1.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"
+
+[[packages]]
+name = "ply"
+version = "3.11"
+
+[[packages.wheels]]
+name = "ply-3.11-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"
+
+[[packages]]
+name = "polars"
+version = "1.32.2"
+
+[[packages.wheels]]
+name = "polars-1.32.2-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/91/58/d2840554ef1c69e06a28ee928bdaa0d6a61af12205ff24c096628f217f99/polars-1.32.2-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "5e1660a584e89e1d60cd89984feca38a695e491a966581fefe8be99c230ea154"
+
+[[packages]]
+name = "prettytable"
+version = "3.16.0"
+
+[[packages.wheels]]
+name = "prettytable-3.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/02/c7/5613524e606ea1688b3bdbf48aa64bafb6d0a4ac3750274c43b6158a390f/prettytable-3.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b5eccfabb82222f5aa46b798ff02a8452cf530a352c31bddfa29be41242863aa"
+
+[[packages]]
+name = "prince"
+version = "0.16.0"
+
+[[packages.wheels]]
+name = "prince-0.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/18/d5/b4480a0f381cbbcfad31f4d118732ab717216857508a730938ee615669a1/prince-0.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7e21a78d4dd06ca3ec526ee714a50b349f26de3fca6b79664150a951b31688f3"
+
+[[packages]]
+name = "priority"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "priority-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"
+
+[[packages]]
+name = "prometheus-client"
+version = "0.21.1"
+
+[[packages.wheels]]
+name = "prometheus_client-0.21.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/c2/ab7d37426c179ceb9aeb109a85cda8948bb269b7561a0be870cc656eefe4/prometheus_client-0.21.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301"
+
+[[packages]]
+name = "prompt-toolkit"
+version = "3.0.51"
+
+[[packages.wheels]]
+name = "prompt_toolkit-3.0.51-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"
+
+[[packages]]
+name = "propcache"
+version = "0.3.1"
+
+[[packages.wheels]]
+name = "propcache-0.3.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a6/2c/a54614d61895ba6dd7ac8f107e2b2a0347259ab29cbf2ecc7b94fa38c4dc/propcache-0.3.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"
+
+[[packages]]
+name = "protobuf"
+version = "6.30.2"
+
+[[packages.wheels]]
+name = "protobuf-6.30.2-cp310-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/97/e9/7b9f1b259d509aef2b833c29a1f3c39185e2bf21c9c1be1cd11c22cb2149/protobuf-6.30.2-cp310-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "7653c99774f73fe6b9301b87da52af0e69783a2e371e8b599b3e9cb4da4b12b9"
+
+[[packages]]
+name = "psutil"
+version = "7.0.0"
+
+[[packages.wheels]]
+name = "psutil-7.0.0-cp37-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"
+
+[[packages]]
+name = "psygnal"
+version = "0.12.0"
+
+[[packages.wheels]]
+name = "psygnal-0.12.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/5e/ae/a3d6815db583b6d05878b3647ea0e2aa21ce6941d03c9d2c6caad1afbcf6/psygnal-0.12.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "d779f20c6977ec9d5b9fece23b4b28bbcf0a7773539a4a176b5527aea5da27c7"
+
+[[packages]]
+name = "ptpython"
+version = "3.0.30"
+
+[[packages.wheels]]
+name = "ptpython-3.0.30-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/05/15/77dfd9a52fa6c87b50232b246df0cfacacc0665c95ebe4a517cc994819f0/ptpython-3.0.30-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bec3045f0285ac817c902ef98d6ece31d3e00a4604ef3fdde07d365c78bde23c"
+
+[[packages]]
+name = "ptyprocess"
+version = "0.7.0"
+
+[[packages.wheels]]
+name = "ptyprocess-0.7.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"
+
+[[packages]]
+name = "pure-eval"
+version = "0.2.3"
+
+[[packages.wheels]]
+name = "pure_eval-0.2.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"
+
+[[packages]]
+name = "pyarrow"
+version = "21.0.0"
+
+[[packages.wheels]]
+name = "pyarrow-21.0.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/01/63/581f2076465e67b23bc5a37d4a2abff8362d389d29d8105832e82c9c811c/pyarrow-21.0.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636"
+
+[[packages]]
+name = "pyasn1"
+version = "0.6.1"
+
+[[packages.wheels]]
+name = "pyasn1-0.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"
+
+[[packages]]
+name = "pyasn1-modules"
+version = "0.4.1"
+
+[[packages.wheels]]
+name = "pyasn1_modules-0.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/77/89/bc88a6711935ba795a679ea6ebee07e128050d6382eaa35a0a47c8032bdc/pyasn1_modules-0.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"
+
+[[packages]]
+name = "pybind11"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "pybind11-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/41/9c/85f50a5476832c3efc67b6d7997808388236ae4754bf53e1749b3bc27577/pybind11-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7c5cac504da5a701b5163f0e6a7ba736c713a096a5378383c5b4b064b753f607"
+
+[[packages]]
+name = "pycodestyle"
+version = "2.12.0"
+
+[[packages.wheels]]
+name = "pycodestyle-2.12.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/55/c4/bf8ede2d1641e0a2e027c6d0c7060e00332851ea772cc5cee42a4a207707/pycodestyle-2.12.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"
+
+[[packages]]
+name = "pycparser"
+version = "2.22"
+
+[[packages.wheels]]
+name = "pycparser-2.22-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"
+
+[[packages]]
+name = "pyct"
+version = "0.5.0"
+
+[[packages.wheels]]
+name = "pyct-0.5.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/75/e7/c7c1e9e1b6b23ca1db7af3c6826d57d8da883021f751edcc9c82143b127a/pyct-0.5.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a4038a8885059ab8cac6f946ea30e0b5e6bdbe0b92b6723f06737035f9d65e8c"
+
+[[packages]]
+name = "pydantic"
+version = "2.11.7"
+
+[[packages.wheels]]
+name = "pydantic-2.11.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"
+
+[[packages]]
+name = "pydantic-ai-slim"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "pydantic_ai_slim-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d8/23/b4d52d83c302859e1e251a8c8a360b993cf8b4818c8b633adaa98b043556/pydantic_ai_slim-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d954ff84cb250d7150a7ed694e4f1f92f820205d036ee006d02fce3e62a3bc4e"
+
+[[packages]]
+name = "pydantic-core"
+version = "2.33.2"
+
+[[packages.wheels]]
+name = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"
+
+[[packages]]
+name = "pydantic-evals"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "pydantic_evals-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b6/6e/8d88e00f624a8348b286b219a292fe3e077ee973660dcff6b4ddd5a04e85/pydantic_evals-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "62035ae3a5321e4d892c7372ef91af0f46b675863e827f011d5cb8550dede400"
+
+[[packages]]
+name = "pydantic-graph"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "pydantic_graph-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a4/cc/e609261763a76f4d23a545afb462847592bc6b4d8eb412990b9b913c073e/pydantic_graph-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "38ad929a0ec205bd7d5875b0b408d4f13448276aa89b6ce2a1143a7552b070ce"
+
+[[packages]]
+name = "pydantic-settings"
+version = "2.8.1"
+
+[[packages.wheels]]
+name = "pydantic_settings-2.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c"
+
+[[packages]]
+name = "pydeck"
+version = "0.9.1"
+
+[[packages.wheels]]
+name = "pydeck-0.9.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038"
+
+[[packages]]
+name = "pydocstyle"
+version = "6.3.0"
+
+[[packages.wheels]]
+name = "pydocstyle-6.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/36/ea/99ddefac41971acad68f14114f38261c1f27dac0b3ec529824ebc739bdaa/pydocstyle-6.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"
+
+[[packages]]
+name = "pydot"
+version = "4.0.1"
+
+[[packages.wheels]]
+name = "pydot-4.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/32/a7125fb28c4261a627f999d5fb4afff25b523800faed2c30979949d6facd/pydot-4.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "869c0efadd2708c0be1f916eb669f3d664ca684bc57ffb7ecc08e70d5e93fee6"
+
+[[packages]]
+name = "pydub"
+version = "0.25.1"
+
+[[packages.wheels]]
+name = "pydub-0.25.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6"
+
+[[packages]]
+name = "pyerfa"
+version = "2.0.1.5"
+
+[[packages.wheels]]
+name = "pyerfa-2.0.1.5-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b4/11/97233cf23ad5411ac6f13b1d6ee3888f90ace4f974d9bf9db887aa428912/pyerfa-2.0.1.5-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "66292d437dcf75925b694977aa06eb697126e7b86553e620371ed3e48b5e0ad0"
+
+[[packages]]
+name = "pyflakes"
+version = "3.2.0"
+
+[[packages.wheels]]
+name = "pyflakes-3.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"
+
+[[packages]]
+name = "pygithub"
+version = "2.6.1"
+
+[[packages.wheels]]
+name = "PyGithub-2.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ac/fc/a444cd19ccc8c4946a512f3827ed0b3565c88488719d800d54a75d541c0b/PyGithub-2.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6f2fa6d076ccae475f9fc392cc6cdbd54db985d4f69b8833a28397de75ed6ca3"
+
+[[packages]]
+name = "pygments"
+version = "2.19.1"
+
+[[packages.wheels]]
+name = "pygments-2.19.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"
+
+[[packages]]
+name = "pyjwt"
+version = "2.10.1"
+
+[[packages.wheels]]
+name = "PyJWT-2.10.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"
+
+[[packages]]
+name = "pylint"
+version = "3.3.6"
+
+[[packages.wheels]]
+name = "pylint-3.3.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/21/9537fc94aee9ec7316a230a49895266cf02d78aa29b0a2efbc39566e0935/pylint-3.3.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8b7c2d3e86ae3f94fb27703d521dd0b9b6b378775991f504d7c3a6275aa0a6a6"
+
+[[packages]]
+name = "pylint-venv"
+version = "3.0.4"
+
+[[packages.wheels]]
+name = "pylint_venv-3.0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a6/10/040e1928236e3d34b26639e3427df88c7249a85aadc621cea2158589b4f8/pylint_venv-3.0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "31006a3df398f58f962c9e5620e756b284e8b2bc490594ce5ee5da41920cb32c"
+
+[[packages]]
+name = "pyls-spyder"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "pyls_spyder-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d0/26/d0975972af1f18c3bb02ec5889191cc09ebb982bcbe45438d90ca763f4ec/pyls_spyder-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1505d975f866a343d0554b6dab41b53717f4b4bc6df450dfd7d48f889fe450b9"
+
+[[packages]]
+name = "pymongo"
+version = "4.10.1"
+
+[[packages.wheels]]
+name = "pymongo-4.10.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/0d/2a/7c24a6144eaa06d18ed52822ea2b0f119fd9267cd1abbb75dae4d89a3803/pymongo-4.10.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "45ee87a4e12337353242bc758accc7fb47a2f2d9ecc0382a61e64c8f01e86708"
+
+[[packages]]
+name = "pympler"
+version = "1.1"
+
+[[packages.wheels]]
+name = "Pympler-1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506"
+
+[[packages]]
+name = "pynacl"
+version = "1.5.0"
+
+[[packages.wheels]]
+name = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/5e/22/d3db169895faaf3e2eda892f005f433a62db2decbcfbc2f61e6517adfa87/PyNaCl-1.5.0-cp36-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"
+
+[[packages]]
+name = "pynndescent"
+version = "0.5.13"
+
+[[packages.wheels]]
+name = "pynndescent-0.5.13-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d2/53/d23a97e0a2c690d40b165d1062e2c4ccc796be458a1ce59f6ba030434663/pynndescent-0.5.13-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "69aabb8f394bc631b6ac475a1c7f3994c54adf3f51cd63b2730fefba5771b949"
+
+[[packages]]
+name = "pyodbc"
+version = "5.2.0"
+
+[[packages.wheels]]
+name = "pyodbc-5.2.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/73/2a/3219c8b7fa3788fc9f27b5fc2244017223cf070e5ab370f71c519adf9120/pyodbc-5.2.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "96d3127f28c0dacf18da7ae009cd48eac532d3dcc718a334b86a3c65f6a5ef5c"
+
+[[packages]]
+name = "pyogrio"
+version = "0.10.0"
+
+[[packages.wheels]]
+name = "pyogrio-0.10.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/27/5d/0deb16d228362a097ee3258d0a887c9c0add4b9678bb4847b08a241e124d/pyogrio-0.10.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "02e54bcfb305af75f829044b0045f74de31b77c2d6546f7aaf96822066147848"
+
+[[packages]]
+name = "pyomo"
+version = "6.9.2"
+
+[[packages.wheels]]
+name = "pyomo-6.9.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/88/0a07233e39357d3d620186485b927074d6d0ae0f64ad72cc5222ae05844e/pyomo-6.9.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "13ebb2f974f97afa626c2712d4f27e09a1c3d18ca11755676b743504a76e5161"
+
+[[packages]]
+name = "pypandoc"
+version = "1.15"
+
+[[packages.wheels]]
+name = "pypandoc-1.15-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/06/0763e0ccc81754d3eadb21b2cb86cf21bdedc9b52698c2ad6785db7f0a4e/pypandoc-1.15-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16"
+
+[[packages]]
+name = "pyparsing"
+version = "3.2.3"
+
+[[packages.wheels]]
+name = "pyparsing-3.2.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"
+
+[[packages]]
+name = "pypdf"
+version = "5.6.0"
+
+[[packages.wheels]]
+name = "pypdf-5.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/71/8b/dc3a72d98c22be7a4cbd664ad14c5a3e6295c2dbdf572865ed61e24b5e38/pypdf-5.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ca6bf446bfb0a2d8d71d6d6bb860798d864c36a29b3d9ae8d7fc7958c59f88e7"
+
+[[packages]]
+name = "pyproj"
+version = "3.7.0"
+
+[[packages.wheels]]
+name = "pyproj-3.7.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f8/33/3c8c6302717096b54aa14ccbb271045ba04629e21cbf348f2f2dc94f69b4/pyproj-3.7.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "10a8dc6ec61af97c89ff032647d743f8dc023645773da42ef43f7ae1125b3509"
+
+[[packages]]
+name = "pyproject-hooks"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "pyproject_hooks-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"
+
+[[packages]]
+name = "pyqt5"
+version = "5.15.11"
+
+[[packages.wheels]]
+name = "PyQt5-5.15.11-cp38-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/56/d5/68eb9f3d19ce65df01b6c7b7a577ad3bbc9ab3a5dd3491a4756e71838ec9/PyQt5-5.15.11-cp38-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517"
+
+[[packages]]
+name = "pyqt5-qt5"
+version = "5.15.2"
+
+[[packages.wheels]]
+name = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/37/97/5d3b222b924fa2ed4c2488925155cd0b03fd5d09ee1cfcf7c553c11c9f66/PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"
+
+[[packages]]
+name = "pyqt5-sip"
+version = "12.17.0"
+
+[[packages.wheels]]
+name = "PyQt5_sip-12.17.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/15/ed/ff94d6b2910e7627380cb1fc9a518ff966e6d78285c8e54c9422b68305db/PyQt5_sip-12.17.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "672c209d05661fab8e17607c193bf43991d268a1eefbc2c4551fbf30fd8bb2ca"
+
+[[packages]]
+name = "pyqtgraph"
+version = "0.13.7"
+
+[[packages.wheels]]
+name = "pyqtgraph-0.13.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/34/5702b3b7cafe99be1d94b42f100e8cc5e6957b761fcb1cf5f72d492851da/pyqtgraph-0.13.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7754edbefb6c367fa0dfb176e2d0610da3ada20aa7a5318516c74af5fb72bf7a"
+
+[[packages]]
+name = "pyqtwebengine"
+version = "5.15.7"
+
+[[packages.wheels]]
+name = "PyQtWebEngine-5.15.7-cp38-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/39/67/0dead50889d905fc99f40e61e5ab7f73746605ce8f74c4fa7fb3fc1d6c5e/PyQtWebEngine-5.15.7-cp38-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bd5e8c426d6f6b352cd15800d64a89b2a4a11e098460b818c7bdcf5e5612e44f"
+
+[[packages]]
+name = "pyqtwebengine-qt5"
+version = "5.15.2"
+
+[[packages.wheels]]
+name = "PyQtWebEngine_Qt5-5.15.2-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e0/db/0f29bd882aee8b5754f3e1ab104d2d09cdd9138a889558b43badcd81ce11/PyQtWebEngine_Qt5-5.15.2-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "24231f19e1595018779977de6722b5c69f3d03f34a5f7574ff21cd1e764ef76d"
+
+[[packages]]
+name = "pyreadline3"
+version = "3.5.4"
+
+[[packages.wheels]]
+name = "pyreadline3-3.5.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"
+
+[[packages]]
+name = "pyserial"
+version = "3.5"
+
+[[packages.wheels]]
+name = "pyserial-3.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"
+
+[[packages]]
+name = "pysocks"
+version = "1.7.1"
+
+[[packages.wheels]]
+name = "PySocks-1.7.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"
+
+[[packages]]
+name = "pyspnego"
+version = "0.11.2"
+
+[[packages.wheels]]
+name = "pyspnego-0.11.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/57/ea/b3c1438839d8724beff7b31ec42b9d041265dc9ca27ccb54477d442bfbcf/pyspnego-0.11.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "74abc1fb51e59360eb5c5c9086e5962174f1072c7a50cf6da0bda9a4bcfdfbd4"
+
+[[packages]]
+name = "pytest"
+version = "8.3.5"
+
+[[packages.wheels]]
+name = "pytest-8.3.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"
+
+[[packages]]
+name = "python-barcode"
+version = "0.15.1"
+
+[[packages.wheels]]
+name = "python_barcode-0.15.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/10/27/9b5c5bb1938d4e6b12f4c95f40ea905c11df3cd58e128e9305397b9a2697/python_barcode-0.15.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "057636fba37369c22852410c8535b36adfbeb965ddfd4e5b6924455d692e0886"
+
+[[packages]]
+name = "python-dateutil"
+version = "2.8.2"
+
+[[packages.wheels]]
+name = "python_dateutil-2.8.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
+
+[[packages]]
+name = "python-dotenv"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "python_dotenv-1.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d"
+
+[[packages]]
+name = "python-json-logger"
+version = "3.3.0"
+
+[[packages.wheels]]
+name = "python_json_logger-3.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7"
+
+[[packages]]
+name = "python-lsp-black"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "python_lsp_black-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/78/44/fef9b4d027b3d6321e6f30b6b5946bef18cd84a96e1d81012ac0f69ea53c/python_lsp_black-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d5efdee45f5fa9e5241f5d4d396cd46127f45c85817916b1fd92c2986652bf7e"
+
+[[packages]]
+name = "python-lsp-jsonrpc"
+version = "1.1.2"
+
+[[packages.wheels]]
+name = "python_lsp_jsonrpc-1.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cb/d9/656659d5b5d5f402b2b174cd0ba9bc827e07ce3c0bf88da65424baf64af8/python_lsp_jsonrpc-1.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c"
+
+[[packages]]
+name = "python-lsp-server"
+version = "1.12.2"
+
+[[packages.wheels]]
+name = "python_lsp_server-1.12.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cb/e7/28010a326ef591e1409daf9d57a47de94156c147ad1befe74d8196d82729/python_lsp_server-1.12.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "750116459449184ba20811167cdf96f91296ae12f1f65ebd975c5c159388111b"
+
+[[packages]]
+name = "python-multipart"
+version = "0.0.20"
+
+[[packages.wheels]]
+name = "python_multipart-0.0.20-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"
+
+[[packages]]
+name = "python-slugify"
+version = "8.0.4"
+
+[[packages.wheels]]
+name = "python_slugify-8.0.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"
+
+[[packages]]
+name = "pythonqwt"
+version = "0.14.5"
+
+[[packages.wheels]]
+name = "pythonqwt-0.14.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/28/e9/1e6e93e1aaaec57d6ef427291e8fb3d9f18ebd91147c24f2b241b01e2def/pythonqwt-0.14.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "be5a9d2e1ba22aaa02eb397c5b3b5e4e1d9ed2c08f45554d8b920d8fc3be6dc7"
+
+[[packages]]
+name = "pytoolconfig"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "pytoolconfig-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/92/44/da239917f5711ca7105f7d7f9e2765716dd883b241529beafc0f28504725/pytoolconfig-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5d8cea8ae1996938ec3eaf44567bbc5ef1bc900742190c439a44a704d6e1b62b"
+
+[[packages]]
+name = "pytz"
+version = "2025.2"
+
+[[packages.wheels]]
+name = "pytz-2025.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"
+
+[[packages]]
+name = "pyuca"
+version = "1.2"
+
+[[packages.wheels]]
+name = "pyuca-1.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/98/88/aeeee34d88f841aca712a8c18fbd62a33eaad8f2dbe535e87f3c829b02f9/pyuca-1.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "abaa12e1bd2c7c68ca8396ff8383bc0654a739cef3ae68fd7af58bf29af0a91e"
+
+[[packages]]
+name = "pyusb"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "pyusb-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430"
+
+[[packages]]
+name = "pyviz-comms"
+version = "3.0.4"
+
+[[packages.wheels]]
+name = "pyviz_comms-3.0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/98/cc/ba051cfaef2525054e3367f2d5ff4df38f8f775125b3eebb82af4060026b/pyviz_comms-3.0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a40d17db26ec13cf975809633804e712bd24b473e77388c193c44043f85d0b25"
+
+[[packages]]
+name = "pywavelets"
+version = "1.8.0"
+
+[[packages.wheels]]
+name = "pywavelets-1.8.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c9/4f/0a709a5732e6cf9297fc87bf545cb879997cde204115f8c0cbc296c5bdd3/pywavelets-1.8.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4dbebcfd55ea8a85b7fc8802d411e75337170422abf6e96019d7e46c394e80e5"
+
+[[packages]]
+name = "pywin32"
+version = "310"
+
+[[packages.wheels]]
+name = "pywin32-310-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"
+
+[[packages]]
+name = "pywin32-ctypes"
+version = "0.2.3"
+
+[[packages.wheels]]
+name = "pywin32_ctypes-0.2.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"
+
+[[packages]]
+name = "pywinpty"
+version = "2.0.15"
+
+[[packages.wheels]]
+name = "pywinpty-2.0.15-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/fb/16/2ab7b3b7f55f3c6929e5f629e1a68362981e4e5fed592a2ed1cb4b4914a5/pywinpty-2.0.15-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408"
+
+[[packages]]
+name = "pyyaml"
+version = "6.0.2"
+
+[[packages.wheels]]
+name = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"
+
+[[packages]]
+name = "pyzmq"
+version = "26.4.0"
+
+[[packages.wheels]]
+name = "pyzmq-26.4.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c6/6c/f289c1789d7bb6e5a3b3bef7b2a55089b8561d17132be7d960d3ff33b14e/pyzmq-26.4.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b"
+
+[[packages]]
+name = "qdarkstyle"
+version = "3.2.3"
+
+[[packages.wheels]]
+name = "QDarkStyle-3.2.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/93/7d/c3c10498430dadcea4def5faddf71cd199e577d20a125e7ef1e9d7bdbbfa/QDarkStyle-3.2.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ea980ee426d594909cf1058306832af71ff6cbad6f69237b036d1550635aefbc"
+
+[[packages]]
+name = "qdldl"
+version = "0.1.7.post5"
+
+[[packages.wheels]]
+name = "qdldl-0.1.7.post5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/08/f7/abac03a09f6848cee6d5dd7a7a8bd1dfed68766ee77f9cbf3e9de596ad68/qdldl-0.1.7.post5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "cc9be378e7bec67d4c62b7fa27cafb4f77d3e5e059d753c3dce0a5ae1ef5fea0"
+
+[[packages]]
+name = "qrcode"
+version = "8.2"
+
+[[packages.wheels]]
+name = "qrcode-8.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/dd/b8/d2d6d731733f51684bbf76bf34dab3b70a9148e8f2cef2bb544fccec681a/qrcode-8.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f"
+
+[[packages]]
+name = "qstylizer"
+version = "0.2.4"
+
+[[packages.wheels]]
+name = "qstylizer-0.2.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2d/ba/2a4e51861942c2bc3be60400c69f6713359c3e307aee4696f2ea47f35811/qstylizer-0.2.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8f384dfe86f9edb0bb596b93663a51f124f0794b94fd54057cc7cf9cea59fb6f"
+
+[[packages]]
+name = "qtawesome"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "qtawesome-1.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/ee/6e6c6715129c929af2d95ddb2e9decf54c1beffe58f336911197aacc0448/qtawesome-1.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a4d689fa071c595aa6184171ce1f0f847677cb8d2db45382c43129f1d72a3d93"
+
+[[packages]]
+name = "qtconsole"
+version = "5.6.1"
+
+[[packages.wheels]]
+name = "qtconsole-5.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c6/8a/635610fb6131bc702229e2780d7b042416866ab78f8ed1ff24c4b23a2f4c/qtconsole-5.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3d22490d9589bace566ad4f3455b61fa2209156f40e87e19e2c3cb64e9264950"
+
+[[packages]]
+name = "qtpy"
+version = "2.4.3"
+
+[[packages.wheels]]
+name = "QtPy-2.4.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/69/76/37c0ccd5ab968a6a438f9c623aeecc84c202ab2fabc6a8fd927580c15b5a/QtPy-2.4.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72095afe13673e017946cc258b8d5da43314197b741ed2890e563cf384b51aa1"
+
+[[packages]]
+name = "quantecon"
+version = "0.8.1"
+
+[[packages.wheels]]
+name = "quantecon-0.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/53/d6/3dd2bea4395988a2a614eebaafd2b478ffd36243e0dbc2bad4aaaf4c1bf7/quantecon-0.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a1f041ed2ed6a9a88e2206998eed85217d3ca903937017cabadfd5a35cbe632e"
+
+[[packages]]
+name = "quart"
+version = "0.20.0"
+
+[[packages.wheels]]
+name = "quart-0.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/e9/cc28f21f52913adf333f653b9e0a3bf9cb223f5083a26422968ba73edd8d/quart-0.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "003c08f551746710acb757de49d9b768986fd431517d0eb127380b656b98b8f1"
+
+[[packages]]
+name = "rapidfuzz"
+version = "3.13.0"
+
+[[packages.wheels]]
+name = "rapidfuzz-3.13.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/96/e3/a98c25c4f74051df4dcf2f393176b8663bfd93c7afc6692c84e96de147a2/rapidfuzz-3.13.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "9a7c6232be5f809cd39da30ee5d24e6cadd919831e6020ec6c2391f4c3bc9264"
+
+[[packages]]
+name = "readme-renderer"
+version = "44.0"
+
+[[packages.wheels]]
+name = "readme_renderer-44.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"
+
+[[packages]]
+name = "redis"
+version = "5.2.1"
+
+[[packages.wheels]]
+name = "redis-5.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3c/5f/fa26b9b2672cbe30e07d9a5bdf39cf16e3b80b42916757c5f92bca88e4ba/redis-5.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"
+
+[[packages]]
+name = "referencing"
+version = "0.36.2"
+
+[[packages.wheels]]
+name = "referencing-0.36.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"
+
+[[packages]]
+name = "regex"
+version = "2024.11.6"
+
+[[packages.wheels]]
+name = "regex-2024.11.6-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"
+
+[[packages]]
+name = "reportlab"
+version = "4.4.2"
+
+[[packages.wheels]]
+name = "reportlab-4.4.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/74/ed990bc9586605d4e46f6b0e0b978a5b8e757aa599e39664bee26d6dc666/reportlab-4.4.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "58e11be387457928707c12153b7e41e52533a5da3f587b15ba8f8fd0805c6ee2"
+
+[[packages]]
+name = "requests"
+version = "2.32.4"
+
+[[packages.wheels]]
+name = "requests-2.32.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"
+
+[[packages]]
+name = "requests-ntlm"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "requests_ntlm-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/5d/836b97537a390cf811b0488490c389c5a614f0a93acb23f347bd37a2d914/requests_ntlm-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4c7534a7d0e482bb0928531d621be4b2c74ace437e88c5a357ceb7452d25a510"
+
+[[packages]]
+name = "requests-toolbelt"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "requests_toolbelt-1.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"
+
+[[packages]]
+name = "rfc3339-validator"
+version = "0.1.4"
+
+[[packages.wheels]]
+name = "rfc3339_validator-0.1.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"
+
+[[packages]]
+name = "rfc3986"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "rfc3986-2.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"
+
+[[packages]]
+name = "rfc3986-validator"
+version = "0.1.1"
+
+[[packages.wheels]]
+name = "rfc3986_validator-0.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"
+
+[[packages]]
+name = "rich"
+version = "14.0.0"
+
+[[packages.wheels]]
+name = "rich-14.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"
+
+[[packages]]
+name = "rope"
+version = "1.13.0"
+
+[[packages.wheels]]
+name = "rope-1.13.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a0/d0/e213e5adfa162e437dff3669131dc476043fc3a22fe99ef891516100610d/rope-1.13.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b435a0c0971244fdcd8741676a9fae697ae614c20cc36003678a7782f25c0d6c"
+
+[[packages]]
+name = "rpds-py"
+version = "0.24.0"
+
+[[packages.wheels]]
+name = "rpds_py-0.24.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f9/12/09e048d1814195e01f354155fb772fb0854bd3450b5f5a82224b3a319f0e/rpds_py-0.24.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a"
+
+[[packages]]
+name = "rsa"
+version = "4.7.2"
+
+[[packages.wheels]]
+name = "rsa-4.7.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e9/93/0c0f002031f18b53af7a6166103c02b9c0667be528944137cc954ec921b3/rsa-4.7.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"
+
+[[packages]]
+name = "rtree"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "rtree-1.4.0-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/ce/c2/362f2cc36a7a57b47380061c23fc109c7222c1a544ffd24cda289ba19673/rtree-1.4.0-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ba83efc7b7563905b1bfdfc14490c4bfb59e92e5e6156bdeb6ec5df5117252f4"
+
+[[packages]]
+name = "rx"
+version = "3.2.0"
+
+[[packages.wheels]]
+name = "Rx-3.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/a9/efeaeca4928a9a56d04d609b5730994d610c82cf4d9dd7aa173e6ef4233e/Rx-3.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "922c5f4edb3aa1beaa47bf61d65d5380011ff6adcd527f26377d05cb73ed8ec8"
+
+[[packages]]
+name = "scikit-image"
+version = "0.25.2"
+
+[[packages.wheels]]
+name = "scikit_image-0.25.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/8a/97/5fcf332e1753831abb99a2525180d3fb0d70918d461ebda9873f66dcc12f/scikit_image-0.25.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "64785a8acefee460ec49a354706db0b09d1f325674107d7fa3eadb663fb56d6f"
+
+[[packages]]
+name = "scikit-learn"
+version = "1.7.1"
+
+[[packages.wheels]]
+name = "scikit_learn-1.7.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e2/47/9291cfa1db1dae9880420d1e07dbc7e8dd4a7cdbc42eaba22512e6bde958/scikit_learn-1.7.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ca6d31fb10e04d50bfd2b50d66744729dbb512d4efd0223b864e2fdbfc4cee11"
+
+[[packages]]
+name = "scipy"
+version = "1.16.0"
+
+[[packages.wheels]]
+name = "scipy-1.16.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7c/a7/4c94bbe91f12126b8bf6709b2471900577b7373a4fd1f431f28ba6f81115/scipy-1.16.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe"
+
+[[packages]]
+name = "scramp"
+version = "1.4.5"
+
+[[packages.wheels]]
+name = "scramp-1.4.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d9/9f/8b2f2749ccfbe4fcef08650896ac47ed919ff25b7ac57b7a1ae7da16c8c3/scramp-1.4.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "50e37c464fc67f37994e35bee4151e3d8f9320e9c204fca83a5d313c121bbbe7"
+
+[[packages]]
+name = "scs"
+version = "3.2.7.post2"
+
+[[packages.wheels]]
+name = "scs-3.2.7.post2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/9d/f9/840ef19a298ef7099f4a692772001f2f552b0917a3fb230f872a1c40ba11/scs-3.2.7.post2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a2c48cd19e39bf87dae0b20a289fff44930458fc2ca2afa0f899058dc41e5545"
+
+[[packages]]
+name = "seaborn"
+version = "0.13.2"
+
+[[packages.wheels]]
+name = "seaborn-0.13.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987"
+
+[[packages]]
+name = "send2trash"
+version = "1.8.3"
+
+[[packages.wheels]]
+name = "Send2Trash-1.8.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9"
+
+[[packages]]
+name = "setuptools"
+version = "80.9.0"
+
+[[packages.wheels]]
+name = "setuptools-80.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"
+
+[[packages]]
+name = "shapely"
+version = "2.1.1"
+
+[[packages.wheels]]
+name = "shapely-2.1.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/12/d9/6d13b8957a17c95794f0c4dfb65ecd0957e6c7131a56ce18d135c1107a52/shapely-2.1.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ab8d878687b438a2f4c138ed1a80941c6ab0029e0f4c785ecfe114413b498a97"
+
+[[packages]]
+name = "shellingham"
+version = "1.5.4"
+
+[[packages.wheels]]
+name = "shellingham-1.5.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"
+
+[[packages]]
+name = "simplejson"
+version = "3.19.3"
+
+[[packages.wheels]]
+name = "simplejson-3.19.3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e2/58/b06226e6b0612f2b1fa13d5273551da259f894566b1eef32249ddfdcce44/simplejson-3.19.3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "3bbcdc438dc1683b35f7a8dc100960c721f922f9ede8127f63bed7dfded4c64c"
+
+[[packages]]
+name = "simpy"
+version = "4.1.1"
+
+[[packages.wheels]]
+name = "simpy-4.1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/48/72/920ed1224c94a8a5a69e6c1275ac7fe4eb911ba8feffddf469f1629d47f3/simpy-4.1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7c5ae380240fd2238671160e4830956f8055830a8317edf5c05e495b3823cd88"
+
+[[packages]]
+name = "six"
+version = "1.17.0"
+
+[[packages.wheels]]
+name = "six-1.17.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"
+
+[[packages]]
+name = "skrub"
+version = "0.6.0"
+
+[[packages.wheels]]
+name = "skrub-0.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/c3/33087009e113b247a2ee58ff3a2a93c51d43cc4f0a3400f6fdb11deea6dc/skrub-0.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bc7155ca02fb4233abce843716b175619d95b94fb7b9ead4b15fc26453d8f646"
+
+[[packages]]
+name = "smmap"
+version = "5.0.2"
+
+[[packages.wheels]]
+name = "smmap-5.0.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"
+
+[[packages]]
+name = "sniffio"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "sniffio-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"
+
+[[packages]]
+name = "snowballstemmer"
+version = "2.2.0"
+
+[[packages.wheels]]
+name = "snowballstemmer-2.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"
+
+[[packages]]
+name = "sortedcontainers"
+version = "2.4.0"
+
+[[packages.wheels]]
+name = "sortedcontainers-2.4.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"
+
+[[packages]]
+name = "sounddevice"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "sounddevice-0.5.1-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/af/9b/15217b04f3b36d30de55fef542389d722de63f1ad81f9c72d8afc98cb6ab/sounddevice-0.5.1-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1"
+
+[[packages]]
+name = "soupsieve"
+version = "2.6"
+
+[[packages.wheels]]
+name = "soupsieve-2.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"
+
+[[packages]]
+name = "sphinx"
+version = "8.1.3"
+
+[[packages.wheels]]
+name = "sphinx-8.1.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"
+
+[[packages]]
+name = "sphinx-rtd-theme"
+version = "3.0.2"
+
+[[packages.wheels]]
+name = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"
+
+[[packages]]
+name = "sphinxcontrib-applehelp"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"
+
+[[packages]]
+name = "sphinxcontrib-devhelp"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"
+
+[[packages]]
+name = "sphinxcontrib-htmlhelp"
+version = "2.1.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"
+
+[[packages]]
+name = "sphinxcontrib-jquery"
+version = "4.1"
+
+[[packages.wheels]]
+name = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"
+
+[[packages]]
+name = "sphinxcontrib-jsmath"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"
+
+[[packages]]
+name = "sphinxcontrib-qthelp"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"
+
+[[packages]]
+name = "sphinxcontrib-serializinghtml"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"
+
+[[packages]]
+name = "spyder"
+version = "6.0.7"
+
+[[packages.wheels]]
+name = "spyder-6.0.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ee/c8/1568fa96351ddad878d42e7487d9637604c7f34030171acf810f47914d9d/spyder-6.0.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b725569bb8ddc7b0aab73d747d85312dc0456978370cc0f9b1a101c0fe4f076b"
+
+[[packages]]
+name = "spyder-kernels"
+version = "3.0.5"
+
+[[packages.wheels]]
+name = "spyder_kernels-3.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/10/2d/b1c88e914ebdec2a9cf066b2c283ee234f4052c31922017407fa8adb89f3/spyder_kernels-3.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9cc808e0ec4426b9ba911128e221fa2234e6c8d6e08526132e90112ff9c2bb7c"
+
+[[packages]]
+name = "sqlalchemy"
+version = "2.0.41"
+
+[[packages.wheels]]
+name = "sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df"
+
+[[packages]]
+name = "sqlite-bro"
+version = "0.13.1"
+
+[[packages.wheels]]
+name = "sqlite_bro-0.13.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/b3/81b91f5b26fff329c59dbf826a87637bd51d1903120427912322f86e7d33/sqlite_bro-0.13.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d"
+
+[[packages]]
+name = "sqlite-fts4"
+version = "1.0.3"
+
+[[packages.wheels]]
+name = "sqlite_fts4-1.0.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/51/29/0096e8b1811aaa78cfb296996f621f41120c21c2f5cd448ae1d54979d9fc/sqlite_fts4-1.0.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0359edd8dea6fd73c848989e1e2b1f31a50fe5f9d7272299ff0e8dbaa62d035f"
+
+[[packages]]
+name = "sqlite-utils"
+version = "3.38"
+
+[[packages.wheels]]
+name = "sqlite_utils-3.38-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4d/eb/f8e8e827805f810838efff3311cccd2601238c5fa3fc35c1f878709e161b/sqlite_utils-3.38-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8a27441015c3b2ef475f555861f7a2592f73bc60d247af9803a11b65fc605bf9"
+
+[[packages]]
+name = "sqlparse"
+version = "0.5.3"
+
+[[packages.wheels]]
+name = "sqlparse-0.5.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"
+
+[[packages]]
+name = "squarify"
+version = "0.4.4"
+
+[[packages.wheels]]
+name = "squarify-0.4.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/3c/eedbe9fb07cc20fd9a8423da14b03bc270d0570b3ba9174a4497156a2152/squarify-0.4.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d7597724e29d48aa14fd2f551060d6b09e1f0a67e4cd3ea329fe03b4c9a56f11"
+
+[[packages]]
+name = "sse-starlette"
+version = "2.4.1"
+
+[[packages.wheels]]
+name = "sse_starlette-2.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e4/f1/6c7eaa8187ba789a6dd6d74430307478d2a91c23a5452ab339b6fbe15a08/sse_starlette-2.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "08b77ea898ab1a13a428b2b6f73cfe6d0e607a7b4e15b9bb23e4a37b087fd39a"
+
+[[packages]]
+name = "sspilib"
+version = "0.2.0"
+
+[[packages.wheels]]
+name = "sspilib-0.2.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/49/ad/40f898075c913c75060c17c9cc6d6b86e8f83b6f5e1e017627b07ff53fcd/sspilib-0.2.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "c39a698491f43618efca8776a40fb7201d08c415c507f899f0df5ada15abefaa"
+
+[[packages]]
+name = "stack-data"
+version = "0.6.3"
+
+[[packages.wheels]]
+name = "stack_data-0.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"
+
+[[packages]]
+name = "starlette"
+version = "0.46.2"
+
+[[packages.wheels]]
+name = "starlette-0.46.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35"
+
+[[packages]]
+name = "statsmodels"
+version = "0.14.4"
+
+[[packages.wheels]]
+name = "statsmodels-0.14.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/1d/eb/cb8b01f5edf8f135eb3d0553d159db113a35b2948d0e51eeb735e7ae09ea/statsmodels-0.14.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "81030108d27aecc7995cac05aa280cf8c6025f6a6119894eef648997936c2dd0"
+
+[[packages]]
+name = "streamlit"
+version = "1.46.1"
+
+[[packages.wheels]]
+name = "streamlit-1.46.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/3b/35400175788cdd6a43c90dce1e7f567eb6843a3ba0612508c0f19ee31f5f/streamlit-1.46.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dffa373230965f87ccc156abaff848d7d731920cf14106f3b99b1ea18076f728"
+
+[[packages]]
+name = "superqt"
+version = "0.7.3"
+
+[[packages.wheels]]
+name = "superqt-0.7.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4f/53/ce8e705a0fca9ff08406d0232409c6dacd09a04cdc5124e33aa3ad97c117/superqt-0.7.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8f7d141665b31baa484747f324fc9fc2d14223f2fefc92ffed6ea35c92221304"
+
+[[packages]]
+name = "sv-ttk"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "sv_ttk-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/3d/be0abc3202e90f282ad465f4e7c6e41bc8dce810ce5d1611566a1e7dfba8/sv_ttk-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"
+
+[[packages]]
+name = "sympy"
+version = "1.14.0"
+
+[[packages.wheels]]
+name = "sympy-1.14.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"
+
+[[packages]]
+name = "tabulate"
+version = "0.9.0"
+
+[[packages.wheels]]
+name = "tabulate-0.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"
+
+[[packages]]
+name = "tblib"
+version = "3.1.0"
+
+[[packages.wheels]]
+name = "tblib-3.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/44/aa5c8b10b2cce7a053018e0d132bd58e27527a0243c4985383d5b6fd93e9/tblib-3.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "670bb4582578134b3d81a84afa1b016128b429f3d48e6cbbaecc9d15675e984e"
+
+[[packages]]
+name = "tenacity"
+version = "9.1.2"
+
+[[packages.wheels]]
+name = "tenacity-9.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"
+
+[[packages]]
+name = "termcolor"
+version = "3.1.0"
+
+[[packages.wheels]]
+name = "termcolor-3.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4f/bd/de8d508070629b6d84a30d01d57e4a65c69aa7f5abe7560b8fad3b50ea59/termcolor-3.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa"
+
+[[packages]]
+name = "terminado"
+version = "0.18.1"
+
+[[packages.wheels]]
+name = "terminado-0.18.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"
+
+[[packages]]
+name = "text-unidecode"
+version = "1.3"
+
+[[packages.wheels]]
+name = "text_unidecode-1.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"
+
+[[packages]]
+name = "textdistance"
+version = "4.6.3"
+
+[[packages.wheels]]
+name = "textdistance-4.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c6/c2/c62601c858010b0513a6434b9be19bd740533a6e861eddfd30b7258d92a0/textdistance-4.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0cb1b2cc8e3339ddc3e0f8c870e49fb49de6ecc42a718917308b3c971f34aa56"
+
+[[packages]]
+name = "thefuzz"
+version = "0.22.1"
+
+[[packages.wheels]]
+name = "thefuzz-0.22.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/4f/1695e70ceb3604f19eda9908e289c687ea81c4fecef4d90a9d1d0f2f7ae9/thefuzz-0.22.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "59729b33556850b90e1093c4cf9e618af6f2e4c985df193fdf3c5b5cf02ca481"
+
+[[packages]]
+name = "threadpoolctl"
+version = "3.6.0"
+
+[[packages.wheels]]
+name = "threadpoolctl-3.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"
+
+[[packages]]
+name = "three-merge"
+version = "0.1.1"
+
+[[packages.wheels]]
+name = "three_merge-0.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/23/be/a52588102605ec52b4e88340d65a290b6465c1dbcd2d943ab149b012908b/three_merge-0.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dd219f4696aa0bbec6099ac3528b4de0450ff9bde862dd8f6d6f52e745f83464"
+
+[[packages]]
+name = "tifffile"
+version = "2025.3.30"
+
+[[packages.wheels]]
+name = "tifffile-2025.3.30-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6e/be/10d23cfd4078fbec6aba768a357eff9e70c0b6d2a07398425985c524ad2a/tifffile-2025.3.30-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0ed6eee7b66771db2d1bfc42262a51b01887505d35539daef118f4ff8c0f629c"
+
+[[packages]]
+name = "tiktoken"
+version = "0.9.0"
+
+[[packages.wheels]]
+name = "tiktoken-0.9.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/de/a8/8f499c179ec900783ffe133e9aab10044481679bb9aad78436d239eee716/tiktoken-0.9.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95"
+
+[[packages]]
+name = "tinycss2"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "tinycss2-1.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"
+
+[[packages]]
+name = "tokenizers"
+version = "0.21.1"
+
+[[packages.wheels]]
+name = "tokenizers-0.21.1-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e6/b6/072a8e053ae600dcc2ac0da81a23548e3b523301a442a6ca900e92ac35be/tokenizers-0.21.1-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "0f0dcbcc9f6e13e675a66d7a5f2f225a736745ce484c1a4e07476a89ccdad382"
+
+[[packages]]
+name = "toml"
+version = "0.10.2"
+
+[[packages.wheels]]
+name = "toml-0.10.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+
+[[packages]]
+name = "tomli"
+version = "2.2.1"
+
+[[packages.wheels]]
+name = "tomli-2.2.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"
+
+[[packages]]
+name = "tomli-w"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "tomli_w-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90"
+
+[[packages]]
+name = "tomlkit"
+version = "0.13.2"
+
+[[packages.wheels]]
+name = "tomlkit-0.13.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"
+
+[[packages]]
+name = "toolz"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "toolz-1.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236"
+
+[[packages]]
+name = "tornado"
+version = "6.5.1"
+
+[[packages.wheels]]
+name = "tornado-6.5.1-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7b/09/6526e32bf1049ee7de3bebba81572673b19a2a8541f795d887e92af1a8bc/tornado-6.5.1-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b"
+
+[[packages]]
+name = "tqdm"
+version = "4.67.1"
+
+[[packages.wheels]]
+name = "tqdm-4.67.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"
+
+[[packages]]
+name = "traitlets"
+version = "5.14.3"
+
+[[packages.wheels]]
+name = "traitlets-5.14.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"
+
+[[packages]]
+name = "traittypes"
+version = "0.2.1"
+
+[[packages.wheels]]
+name = "traittypes-0.2.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9c/d1/8d5bd662703cc1764d986f6908a608777305946fa634d34c470cd4a1e729/traittypes-0.2.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1340af133810b6eee1a2eb2e988f862b0d12b6c2d16f282aaf3207b782134c2e"
+
+[[packages]]
+name = "trio"
+version = "0.30.0"
+
+[[packages.wheels]]
+name = "trio-0.30.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/69/8e/3f6dfda475ecd940e786defe6df6c500734e686c9cd0a0f8ef6821e9b2f2/trio-0.30.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3bf4f06b8decf8d3cf00af85f40a89824669e2d033bb32469d34840edcfc22a5"
+
+[[packages]]
+name = "trove-classifiers"
+version = "2025.5.9.12"
+
+[[packages.wheels]]
+name = "trove_classifiers-2025.5.9.12-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/92/ef/c6deb083748be3bcad6f471b6ae983950c161890bf5ae1b2af80cc56c530/trove_classifiers-2025.5.9.12-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e381c05537adac78881c8fa345fd0e9970159f4e4a04fcc42cfd3129cca640ce"
+
+[[packages]]
+name = "twine"
+version = "6.1.0"
+
+[[packages.wheels]]
+name = "twine-6.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7c/b6/74e927715a285743351233f33ea3c684528a0d374d2e43ff9ce9585b73fe/twine-6.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"
+
+[[packages]]
+name = "typer"
+version = "0.15.2"
+
+[[packages.wheels]]
+name = "typer-0.15.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc"
+
+[[packages]]
+name = "types-python-dateutil"
+version = "2.9.0.20240316"
+
+[[packages.wheels]]
+name = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c7/1b/af4f4c4f3f7339a4b7eb3c0ab13416db98f8ac09de3399129ee5fdfa282b/types_python_dateutil-2.9.0.20240316-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"
+
+[[packages]]
+name = "types-requests"
+version = "2.32.0.20250328"
+
+[[packages.wheels]]
+name = "types_requests-2.32.0.20250328-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cc/15/3700282a9d4ea3b37044264d3e4d1b1f0095a4ebf860a99914fd544e3be3/types_requests-2.32.0.20250328-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72ff80f84b15eb3aa7a8e2625fffb6a93f2ad5a0c20215fc1dcfa61117bcb2a2"
+
+[[packages]]
+name = "typing-extensions"
+version = "4.13.2"
+
+[[packages.wheels]]
+name = "typing_extensions-4.13.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"
+
+[[packages]]
+name = "typing-inspection"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "typing_inspection-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"
+
+[[packages]]
+name = "tzdata"
+version = "2025.2"
+
+[[packages.wheels]]
+name = "tzdata-2025.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"
+
+[[packages]]
+name = "tzlocal"
+version = "5.3.1"
+
+[[packages.wheels]]
+name = "tzlocal-5.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d"
+
+[[packages]]
+name = "uc-micro-py"
+version = "1.0.3"
+
+[[packages.wheels]]
+name = "uc_micro_py-1.0.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5"
+
+[[packages]]
+name = "ujson"
+version = "5.10.0"
+
+[[packages.wheels]]
+name = "ujson-5.10.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/d7/72/6cb6728e2738c05bbe9bd522d6fc79f86b9a28402f38663e85a28fddd4a0/ujson-5.10.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"
+
+[[packages]]
+name = "umap-learn"
+version = "0.5.7"
+
+[[packages.wheels]]
+name = "umap_learn-0.5.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3c/8f/671c0e1f2572ba625cbcc1faeba9435e00330c3d6962858711445cf1e817/umap_learn-0.5.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6a7e0be2facfa365a5ed6588447102bdbef32a0ef449535c25c97ea7e680073c"
+
+[[packages]]
+name = "uncertainties"
+version = "3.2.2"
+
+[[packages.wheels]]
+name = "uncertainties-3.2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fa/fc/97711d2a502881d871e3cf2d2645e21e7f8e4d4fd9a56937557790cade6a/uncertainties-3.2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fd8543355952f4052786ed4150acaf12e23117bd0f5bd03ea07de466bce646e7"
+
+[[packages]]
+name = "uri-template"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "uri_template-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"
+
+[[packages]]
+name = "urllib3"
+version = "2.4.0"
+
+[[packages.wheels]]
+name = "urllib3-2.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
+
+[[packages]]
+name = "uvicorn"
+version = "0.34.2"
+
+[[packages.wheels]]
+name = "uvicorn-0.34.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403"
+
+[[packages]]
+name = "vega-datasets"
+version = "0.9.0"
+
+[[packages.wheels]]
+name = "vega_datasets-0.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e6/9f/ca52771fe972e0dcc5167fedb609940e01516066938ff2ee28b273ae4f29/vega_datasets-0.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3d7c63917be6ca9b154b565f4779a31fedce57b01b5b9d99d8a34a7608062a1d"
+
+[[packages]]
+name = "waitress"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "waitress-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5b/a9/485c953a1ac4cb98c28e41fd2c7184072df36bbf99734a51d44d04176878/waitress-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"
+
+[[packages]]
+name = "watchdog"
+version = "6.0.0"
+
+[[packages.wheels]]
+name = "watchdog-6.0.0-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"
+
+[[packages]]
+name = "wcwidth"
+version = "0.2.13"
+
+[[packages.wheels]]
+name = "wcwidth-0.2.13-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"
+
+[[packages]]
+name = "webcolors"
+version = "24.11.1"
+
+[[packages.wheels]]
+name = "webcolors-24.11.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9"
+
+[[packages]]
+name = "webencodings"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "webencodings-0.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"
+
+[[packages]]
+name = "websocket-client"
+version = "1.8.0"
+
+[[packages.wheels]]
+name = "websocket_client-1.8.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"
+
+[[packages]]
+name = "websockets"
+version = "14.2"
+
+[[packages.wheels]]
+name = "websockets-14.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f"
+
+[[packages]]
+name = "werkzeug"
+version = "3.1.3"
+
+[[packages.wheels]]
+name = "werkzeug-3.1.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"
+
+[[packages]]
+name = "whatthepatch"
+version = "1.0.7"
+
+[[packages.wheels]]
+name = "whatthepatch-1.0.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8e/93/af1d6ccb69ab6b5a00e03fa0cefa563f9862412667776ea15dd4eece3a90/whatthepatch-1.0.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1b6f655fd31091c001c209529dfaabbabdbad438f5de14e3951266ea0fc6e7ed"
+
+[[packages]]
+name = "wheel"
+version = "0.45.1"
+
+[[packages.wheels]]
+name = "wheel-0.45.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"
+
+[[packages]]
+name = "widgetsnbextension"
+version = "4.0.14"
+
+[[packages.wheels]]
+name = "widgetsnbextension-4.0.14-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575"
+
+[[packages]]
+name = "wordcloud"
+version = "1.9.4"
+
+[[packages.wheels]]
+name = "wordcloud-1.9.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/84/47/d482f7d2decc6e59e69e105b12c53d6d2967f0d703e664484c5f2f87fca8/wordcloud-1.9.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8c9a5af2fbcf029a19e827adbee58e86efe7536dca7a42380a8601113a86069b"
+
+[[packages]]
+name = "wppm"
+version = "17.2.20250823"
+
+[[packages.wheels]]
+name = "wppm-17.2.20250823-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ae/a9/2581cc7f91354eada41367bf68b91b1b7fba6cb6fb469f500dbaf6191539/wppm-17.2.20250823-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3"
+
+[[packages]]
+name = "wrapt"
+version = "1.16.0"
+
+[[packages.wheels]]
+name = "wrapt-1.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/21/abdedb4cdf6ff41ebf01a74087740a709e2edb146490e4d9beea054b0b7a/wrapt-1.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"
+
+[[packages]]
+name = "wsproto"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "wsproto-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"
+
+[[packages]]
+name = "xarray"
+version = "2025.7.1"
+
+[[packages.wheels]]
+name = "xarray-2025.7.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b2/ea/9554e5fb78eda4dbc9e9ccaf23034166fe3e9ea9af82ea6204b9578434bc/xarray-2025.7.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e8647b659e53bd350d7c5a91c34dd4122ad6a3ca0bc41399d424a7c0273c7635"
+
+[[packages]]
+name = "xlsxwriter"
+version = "3.2.5"
+
+[[packages.wheels]]
+name = "xlsxwriter-3.2.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fa/34/a22e6664211f0c8879521328000bdcae9bf6dbafa94a923e531f6d5b3f73/xlsxwriter-3.2.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f4824234e1eaf9d95df9a8fe974585ff91d0f5e3d3f12ace5b71e443c1c6abd"
+
+[[packages]]
+name = "xyzservices"
+version = "2023.10.1"
+
+[[packages.wheels]]
+name = "xyzservices-2023.10.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/c3/e06dfa46464cce3eda4b86df8847cab99d9bc545c76807ee689545187a4c/xyzservices-2023.10.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6a4c38d3a9f89d3e77153eff9414b36a8ee0850c9e8b85796fd1b2a85b8dfd68"
+
+[[packages]]
+name = "yapf"
+version = "0.40.1"
+
+[[packages.wheels]]
+name = "yapf-0.40.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/23/75/c374517c09e31bf22d3b3f156d73e0f38d08e29b2afdd607cef5f1e10aa9/yapf-0.40.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313"
+
+[[packages]]
+name = "yarl"
+version = "1.18.3"
+
+[[packages.wheels]]
+name = "yarl-1.18.3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"
+
+[[packages]]
+name = "yt-dlp"
+version = "2025.2.19"
+
+[[packages.wheels]]
+name = "yt_dlp-2025.2.19-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/45/6d1b759e68f5363b919828fb0e0c167a1cd5003b5b7c74cc0f0c2096be4f/yt_dlp-2025.2.19-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3ed218eaeece55e9d715afd41abc450dc406ee63bf79355169dfde312d38fdb8"
+
+[[packages]]
+name = "zict"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "zict-3.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/80/ab/11a76c1e2126084fde2639514f24e6111b789b0bfa4fc6264a8975c7e1f1/zict-3.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5796e36bd0e0cc8cf0fbc1ace6a68912611c1dbd74750a3f3026b9b9d6a327ae"
+
+[[packages]]
+name = "zipp"
+version = "3.21.0"
+
+[[packages.wheels]]
+name = "zipp-3.21.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/1a/7e4798e9339adc931158c9d69ecc34f5e6791489d469f5e50ec15e35f458/zipp-3.21.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"
+
+[[packages]]
+name = "zstandard"
+version = "0.23.0"
+
+[[packages.wheels]]
+name = "zstandard-0.23.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a2/bf/c6aaba098e2d04781e8f4f7c0ba3c7aa73d00e4c436bcc0cf059a66691d1/zstandard-0.23.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b"
diff --git a/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0whlb3_wheels.toml b/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0whlb3_wheels.toml
new file mode 100644
index 00000000..c195ce96
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/pylock.64-3_13_7_0whlb3_wheels.toml
@@ -0,0 +1,5381 @@
+lock-version = "1.0"
+created-by = "pip"
+
+[[packages]]
+name = "absl-py"
+version = "2.3.0"
+
+[[packages.wheels]]
+name = "absl_py-2.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/04/9d75e1d3bb4ab8ec67ff10919476ccdee06c098bcfcf3a352da5f985171d/absl_py-2.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9824a48b654a306168f63e0d97714665f8490b8d89ec7bf2efc24bf67cf579b3"
+
+[[packages]]
+name = "adbc-driver-manager"
+version = "1.6.0"
+
+[[packages.wheels]]
+name = "adbc_driver_manager-1.6.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/bf/5f/a04791038cb659c8e1e7fb4a22d75a9fd3e3109a22822bd80beea0046dc4/adbc_driver_manager-1.6.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "0e8ffb182fafe1e6ae12964a833700daacc55f7abfdc2ada8b5214b18108d87b"
+
+[[packages]]
+name = "aiofiles"
+version = "24.1.0"
+
+[[packages.wheels]]
+name = "aiofiles-24.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"
+
+[[packages]]
+name = "aiohappyeyeballs"
+version = "2.6.1"
+
+[[packages.wheels]]
+name = "aiohappyeyeballs-2.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"
+
+[[packages]]
+name = "aiohttp"
+version = "3.11.18"
+
+[[packages.wheels]]
+name = "aiohttp-3.11.18-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/1e/3c/143831b32cd23b5263a995b2a1794e10aa42f8a895aae5074c20fda36c07/aiohttp-3.11.18-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01"
+
+[[packages]]
+name = "aiosignal"
+version = "1.3.2"
+
+[[packages.wheels]]
+name = "aiosignal-1.3.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"
+
+[[packages]]
+name = "aiosqlite"
+version = "0.21.0"
+
+[[packages.wheels]]
+name = "aiosqlite-0.21.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f5/10/6c25ed6de94c49f88a91fa5018cb4c0f3625f31d5be9f771ebe5cc7cd506/aiosqlite-0.21.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0"
+
+[[packages]]
+name = "alabaster"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "alabaster-1.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"
+
+[[packages]]
+name = "alembic"
+version = "1.16.1"
+
+[[packages.wheels]]
+name = "alembic-1.16.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/59/565286efff3692c5716c212202af61466480f6357c4ae3089d4453bff1f3/alembic-1.16.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0cdd48acada30d93aa1035767d67dff25702f8de74d7c3919f2e8492c8db2e67"
+
+[[packages]]
+name = "altair"
+version = "5.5.0"
+
+[[packages.wheels]]
+name = "altair-5.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/aa/f3/0b6ced594e51cc95d8c1fc1640d3623770d01e4969d29c0bd09945fafefa/altair-5.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c"
+
+[[packages]]
+name = "annotated-types"
+version = "0.7.0"
+
+[[packages.wheels]]
+name = "annotated_types-0.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"
+
+[[packages]]
+name = "ansicolors"
+version = "1.1.8"
+
+[[packages.wheels]]
+name = "ansicolors-1.1.8-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/53/18/a56e2fe47b259bb52201093a3a9d4a32014f9d85071ad07e9d60600890ca/ansicolors-1.1.8-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187"
+
+[[packages]]
+name = "anthropic"
+version = "0.64.0"
+
+[[packages.wheels]]
+name = "anthropic-0.64.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a9/b2/2d268bcd5d6441df9dc0ebebc67107657edb8b0150d3fda1a5b81d1bec45/anthropic-0.64.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6f5f7d913a6a95eb7f8e1bda4e75f76670e8acd8d4cd965e02e2a256b0429dd1"
+
+[[packages]]
+name = "anyio"
+version = "4.9.0"
+
+[[packages.wheels]]
+name = "anyio-4.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"
+
+[[packages]]
+name = "anywidget"
+version = "0.9.18"
+
+[[packages.wheels]]
+name = "anywidget-0.9.18-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2b/f0/09a30ca0551af20c7cefa7464b7ccb6f5407a550b83c4dcb15c410814849/anywidget-0.9.18-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "944b82ef1dd17b8ff0fb6d1f199f613caf9111338e6e2857da478f6e73770cb8"
+
+[[packages]]
+name = "appdirs"
+version = "1.4.4"
+
+[[packages.wheels]]
+name = "appdirs-1.4.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
+
+[[packages]]
+name = "argcomplete"
+version = "3.6.2"
+
+[[packages.wheels]]
+name = "argcomplete-3.6.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/da/e42d7a9d8dd33fa775f467e4028a47936da2f01e4b0e561f9ba0d74cb0ca/argcomplete-3.6.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "65b3133a29ad53fb42c48cf5114752c7ab66c1c38544fdf6460f450c09b42591"
+
+[[packages]]
+name = "argon2-cffi"
+version = "25.1.0"
+
+[[packages.wheels]]
+name = "argon2_cffi-25.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741"
+
+[[packages]]
+name = "argon2-cffi-bindings"
+version = "21.2.0"
+
+[[packages.wheels]]
+name = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"
+
+[[packages]]
+name = "array-api-compat"
+version = "1.12.0"
+
+[[packages.wheels]]
+name = "array_api_compat-1.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e0/b1/0542e0cab6f49f151a2d7a42400f84f706fc0b64e85dc1f56708b2e9fd37/array_api_compat-1.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0b4795b6944a9507fde54679f9350e2ad2b1e2acf4a2408a098cdc27f890a8b"
+
+[[packages]]
+name = "arrow"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "arrow-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"
+
+[[packages]]
+name = "asgi-csrf"
+version = "0.11"
+
+[[packages.wheels]]
+name = "asgi_csrf-0.11-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/1c/5d954baaf144852a4762368b37c06202b277378ea412acc5565f69acc9e9/asgi_csrf-0.11-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "03ac140115f39d4295288a9adf74fdc6ae607f6ef44abee8466520458207242b"
+
+[[packages]]
+name = "asgiref"
+version = "3.8.1"
+
+[[packages.wheels]]
+name = "asgiref-3.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"
+
+[[packages]]
+name = "asn1crypto"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "asn1crypto-1.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c9/7f/09065fd9e27da0eda08b4d6897f1c13535066174cc023af248fc2a8d5e5a/asn1crypto-1.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"
+
+[[packages]]
+name = "asteval"
+version = "1.0.5"
+
+[[packages.wheels]]
+name = "asteval-1.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0a/0d/2c6aaab67ac566d76322e87827d707214c5f6ffb5a4fcd456a8633da1788/asteval-1.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "082b95312578affc8a6d982f7d92b7ac5de05634985c87e7eedd3188d31149fa"
+
+[[packages]]
+name = "astroid"
+version = "3.3.9"
+
+[[packages.wheels]]
+name = "astroid-3.3.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/de/80/c749efbd8eef5ea77c7d6f1956e8fbfb51963b7f93ef79647afd4d9886e3/astroid-3.3.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d05bfd0acba96a7bd43e222828b7d9bc1e138aaeb0649707908d3702a9831248"
+
+[[packages]]
+name = "astropy"
+version = "7.1.0"
+
+[[packages.wheels]]
+name = "astropy-7.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/0b/dd/d9c55247172f7156696d85c9146b64b41c30405bf86b775a731bed4d52f8/astropy-7.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8e317f34e33a8f5517bc9fc6fbc005f42730d3be7d2820ef41e0468bcb796843"
+
+[[packages]]
+name = "astropy-iers-data"
+version = "0.2025.6.9.0.39.3"
+
+[[packages.wheels]]
+name = "astropy_iers_data-0.2025.6.9.0.39.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/39/18/83a74b38e1cfd2291f43daf0cf9ea59cd8dd8ded912c2e56141e6224d708/astropy_iers_data-0.2025.6.9.0.39.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "76855f5572707b8d25f77a0ede2b330b7ef9863bc963e3eda86321e4e32df802"
+
+[[packages]]
+name = "asttokens"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "asttokens-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"
+
+[[packages]]
+name = "async-lru"
+version = "2.0.5"
+
+[[packages.wheels]]
+name = "async_lru-2.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943"
+
+[[packages]]
+name = "asyncssh"
+version = "2.21.0"
+
+[[packages.wheels]]
+name = "asyncssh-2.21.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/99/56/db25216aa7f385ec71fdc489af80812171515cddbe68c0e515e98a291390/asyncssh-2.21.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cf7f3dfa52b2cb4ad31f0d77ff0d0a8fdd850203da84a0e72e62c36fdd4daf4b"
+
+[[packages]]
+name = "atomicwrites"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "atomicwrites-1.4.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/a0/da5f49008ec6e9a658dbf5d7310a4debd397bce0b4db03cf8a410066bb87/atomicwrites-1.4.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"
+
+[[packages]]
+name = "attrs"
+version = "25.3.0"
+
+[[packages.wheels]]
+name = "attrs-25.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"
+
+[[packages]]
+name = "autopep8"
+version = "2.0.4"
+
+[[packages.wheels]]
+name = "autopep8-2.0.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d8/f2/e63c9f9c485cd90df8e4e7ae90fa3be2469c9641888558c7b45fa98a76f8/autopep8-2.0.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb"
+
+[[packages]]
+name = "azure-core"
+version = "1.34.0"
+
+[[packages.wheels]]
+name = "azure_core-1.34.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/9e/5c87b49f65bb16571599bc789857d0ded2f53014d3392bc88a5d1f3ad779/azure_core-1.34.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0615d3b756beccdb6624d1c0ae97284f38b78fb59a2a9839bf927c66fbbdddd6"
+
+[[packages]]
+name = "azure-cosmos"
+version = "4.9.0"
+
+[[packages.wheels]]
+name = "azure_cosmos-4.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/dc/380f843744535497acd0b85aacb59565c84fc28bf938c8d6e897a858cd95/azure_cosmos-4.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3b60eaa01a16a857d0faf0cec304bac6fa8620a81bc268ce760339032ef617fe"
+
+[[packages]]
+name = "azure-identity"
+version = "1.23.0"
+
+[[packages.wheels]]
+name = "azure_identity-1.23.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/16/a51d47780f41e4b87bb2d454df6aea90a44a346e918ac189d3700f3d728d/azure_identity-1.23.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dbbeb64b8e5eaa81c44c565f264b519ff2de7ff0e02271c49f3cb492762a50b0"
+
+[[packages]]
+name = "babel"
+version = "2.17.0"
+
+[[packages.wheels]]
+name = "babel-2.17.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"
+
+[[packages]]
+name = "baresql"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "baresql-1.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d6/d2/fe24bcd99d97bddbbccdf191edf4e84c0fdfe894dfff9f54b05f36096ebb/baresql-1.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a24d17f46beb47c221f328f7e06710e3896c6203a8e1909788d7128f27b86f01"
+
+[[packages]]
+name = "bcrypt"
+version = "4.3.0"
+
+[[packages.wheels]]
+name = "bcrypt-4.3.0-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a9/cf/45fb5261ece3e6b9817d3d82b2f343a505fd58674a92577923bc500bd1aa/bcrypt-4.3.0-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b"
+
+[[packages]]
+name = "beautifulsoup4"
+version = "4.13.4"
+
+[[packages.wheels]]
+name = "beautifulsoup4-4.13.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b"
+
+[[packages]]
+name = "binaryornot"
+version = "0.4.4"
+
+[[packages.wheels]]
+name = "binaryornot-0.4.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"
+
+[[packages]]
+name = "black"
+version = "25.1.0"
+
+[[packages.wheels]]
+name = "black-25.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"
+
+[[packages]]
+name = "bleach"
+version = "6.2.0"
+
+[[packages.wheels]]
+name = "bleach-6.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"
+
+[[packages]]
+name = "blinker"
+version = "1.9.0"
+
+[[packages.wheels]]
+name = "blinker-1.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"
+
+[[packages]]
+name = "bokeh"
+version = "3.7.3"
+
+[[packages.wheels]]
+name = "bokeh-3.7.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/91/48/08b2382e739236aa3360b7976360ba3e0c043b6234e25951c18c1eb6fa06/bokeh-3.7.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b0e79dd737f088865212e4fdcb0f3b95d087f0f088bf8ca186a300ab1641e2c7"
+
+[[packages]]
+name = "branca"
+version = "0.8.1"
+
+[[packages.wheels]]
+name = "branca-0.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f8/9d/91cddd38bd00170aad1a4b198c47b4ed716be45c234e09b835af41f4e717/branca-0.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d29c5fab31f7c21a92e34bf3f854234e29fecdcf5d2df306b616f20d816be425"
+
+[[packages]]
+name = "brotli"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "Brotli-1.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7e/c1/ec214e9c94000d1c1974ec67ced1c970c148aa6b8d8373066123fc3dbf06/Brotli-1.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b"
+
+[[packages]]
+name = "build"
+version = "1.2.2.post1"
+
+[[packages.wheels]]
+name = "build-1.2.2.post1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"
+
+[[packages]]
+name = "cachetools"
+version = "5.5.2"
+
+[[packages.wheels]]
+name = "cachetools-5.5.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"
+
+[[packages]]
+name = "certifi"
+version = "2025.4.26"
+
+[[packages.wheels]]
+name = "certifi-2025.4.26-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"
+
+[[packages]]
+name = "cffi"
+version = "1.17.1"
+
+[[packages.wheels]]
+name = "cffi-1.17.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"
+
+[[packages]]
+name = "chardet"
+version = "5.2.0"
+
+[[packages.wheels]]
+name = "chardet-5.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"
+
+[[packages]]
+name = "charset-normalizer"
+version = "3.4.2"
+
+[[packages.wheels]]
+name = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"
+
+[[packages]]
+name = "clarabel"
+version = "0.10.0"
+
+[[packages.wheels]]
+name = "clarabel-0.10.0-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e6/ba/67a0defb70ed910877049e915e6738fc0432edd5e46b97743ce78a1e5b95/clarabel-0.10.0-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "7871b6f499ad66f71d4e7fb40754c4d986d4316f242beb62ff4f63a69785a50c"
+
+[[packages]]
+name = "click"
+version = "8.2.1"
+
+[[packages.wheels]]
+name = "click-8.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"
+
+[[packages]]
+name = "click-default-group"
+version = "1.2.4"
+
+[[packages.wheels]]
+name = "click_default_group-1.2.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/1a/aff8bb287a4b1400f69e09a53bd65de96aa5cee5691925b38731c67fc695/click_default_group-1.2.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f"
+
+[[packages]]
+name = "cloudpickle"
+version = "3.1.1"
+
+[[packages.wheels]]
+name = "cloudpickle-3.1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/e8/64c37fadfc2816a7701fa8a6ed8d87327c7d54eacfbfb6edab14a2f2be75/cloudpickle-3.1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c8c5a44295039331ee9dad40ba100a9c7297b6f988e50e87ccdf3765a668350e"
+
+[[packages]]
+name = "cohere"
+version = "5.16.1"
+
+[[packages.wheels]]
+name = "cohere-5.16.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/c6/72309ac75f3567425ca31a601ad394bfee8d0f4a1569dfbc80cbb2890d07/cohere-5.16.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "37e2c1d69b1804071b5e5f5cb44f8b74127e318376e234572d021a1a729c6baa"
+
+[[packages]]
+name = "colorama"
+version = "0.4.6"
+
+[[packages.wheels]]
+name = "colorama-0.4.6-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
+
+[[packages]]
+name = "coloredlogs"
+version = "7.3.1"
+
+[[packages.wheels]]
+name = "coloredlogs-7.3.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/b3/3ea34a2248fa707d04900195589357ccb924ae8db8810ecf26e17c4cb2e3/coloredlogs-7.3.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f08ee2a2cef08163ddd24596e48cba2243937abf915d7fb37d62254596b816a9"
+
+[[packages]]
+name = "colorlog"
+version = "6.9.0"
+
+[[packages.wheels]]
+name = "colorlog-6.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e3/51/9b208e85196941db2f0654ad0357ca6388ab3ed67efdbfc799f35d1f83aa/colorlog-6.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff"
+
+[[packages]]
+name = "comm"
+version = "0.2.2"
+
+[[packages.wheels]]
+name = "comm-0.2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"
+
+[[packages]]
+name = "contourpy"
+version = "1.3.2"
+
+[[packages.wheels]]
+name = "contourpy-1.3.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9"
+
+[[packages]]
+name = "cookiecutter"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "cookiecutter-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d"
+
+[[packages]]
+name = "cryptography"
+version = "45.0.5"
+
+[[packages.wheels]]
+name = "cryptography-45.0.5-cp311-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/1f/10/197da38a5911a48dd5389c043de4aec4b3c94cb836299b01253940788d78/cryptography-45.0.5-cp311-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63"
+
+[[packages]]
+name = "cvxpy"
+version = "1.6.5"
+
+[[packages.wheels]]
+name = "cvxpy-1.6.5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a0/3c/86682ec2b72f72e46e359903d7c18686e5314aa4baa96c77f6595c58fb03/cvxpy-1.6.5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "51161b0e8b0d83dc07355bab938bd0734dd5531c98dca8d6faaa8b847c651339"
+
+[[packages]]
+name = "cycler"
+version = "0.12.1"
+
+[[packages.wheels]]
+name = "cycler-0.12.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"
+
+[[packages]]
+name = "cython"
+version = "3.1.2"
+
+[[packages.wheels]]
+name = "cython-3.1.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c2/94/65ba40faeafe74845ba22b61aff7d73475671c3bd24bffc6cba53f3b0063/cython-3.1.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8ab1319c77f15b0ae04b3fb03588df3afdec4cf79e90eeea5c961e0ebd8fdf72"
+
+[[packages]]
+name = "cytoolz"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "cytoolz-1.0.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297"
+
+[[packages]]
+name = "dask"
+version = "2025.7.0"
+
+[[packages.wheels]]
+name = "dask-2025.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b3/f9/3e04725358c17329652da8c1b2dbd88de723f3dc78bf52ca6d28d52c9279/dask-2025.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "073c29c4e99c2400a39a8a67874f35c1d15bf7af9ae3d0c30af3c7c1199f24ae"
+
+[[packages]]
+name = "datasette"
+version = "0.65.1"
+
+[[packages.wheels]]
+name = "datasette-0.65.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/08/f7/fc15b9ddc7a2cafe546f0e2696d71940d7604a128e2f903e98238c3435f7/datasette-0.65.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ba7adf717ddcc24a2a8ac57890fffd384a2ebb909b342e4f731ba09eba764305"
+
+[[packages]]
+name = "datasette-graphql"
+version = "2.2"
+
+[[packages.wheels]]
+name = "datasette_graphql-2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f1/12/e8fb59d77c59ec47a2aa53a6d4ac57ad55fce2b48c8397c2866c3f2c66cd/datasette_graphql-2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cd9f61afdcaab1ce4ff6775296e6ece99305bf05cbfae4c1c938a6c9e60cd485"
+
+[[packages]]
+name = "deap"
+version = "1.4.2"
+
+[[packages.wheels]]
+name = "deap-1.4.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/6e/22/614264336b00b1a01447e31c941fd4576478b5d32184dbb552db27b1c2a1/deap-1.4.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "1abab976c75b0f18c36e81f968fcc77fac69fc9bedbab8be3323ca376f6fcfa4"
+
+[[packages]]
+name = "debugpy"
+version = "1.8.14"
+
+[[packages.wheels]]
+name = "debugpy-1.8.14-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e0/62/a7b4a57013eac4ccaef6977966e6bec5c63906dd25a86e35f155952e29a1/debugpy-1.8.14-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e"
+
+[[packages]]
+name = "decorator"
+version = "5.2.1"
+
+[[packages.wheels]]
+name = "decorator-5.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"
+
+[[packages]]
+name = "defusedxml"
+version = "0.7.1"
+
+[[packages.wheels]]
+name = "defusedxml-0.7.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
+
+[[packages]]
+name = "deprecated"
+version = "1.2.18"
+
+[[packages.wheels]]
+name = "Deprecated-1.2.18-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"
+
+[[packages]]
+name = "diff-match-patch"
+version = "20241021"
+
+[[packages.wheels]]
+name = "diff_match_patch-20241021-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f7/bb/2aa9b46a01197398b901e458974c20ed107935c26e44e37ad5b0e5511e44/diff_match_patch-20241021-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782"
+
+[[packages]]
+name = "dill"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "dill-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"
+
+[[packages]]
+name = "distributed"
+version = "2025.7.0"
+
+[[packages.wheels]]
+name = "distributed-2025.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/dc/9f033526ed98b65cda8adbd10b6eeeca0659203f67bd3e065ce172008887/distributed-2025.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "51b74526c2bee409ca968ee5532c79de1c1a1713664f5ccf90bdd81f17cfdc73"
+
+[[packages]]
+name = "distro"
+version = "1.9.0"
+
+[[packages.wheels]]
+name = "distro-1.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"
+
+[[packages]]
+name = "django"
+version = "5.2.1"
+
+[[packages.wheels]]
+name = "django-5.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/90/92/7448697b5838b3a1c6e1d2d6a673e908d0398e84dc4f803a2ce11e7ffc0f/django-5.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a9b680e84f9a0e71da83e399f1e922e1ab37b2173ced046b541c72e1589a5961"
+
+[[packages]]
+name = "dnspython"
+version = "2.7.0"
+
+[[packages.wheels]]
+name = "dnspython-2.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"
+
+[[packages]]
+name = "docstring-to-markdown"
+version = "0.17"
+
+[[packages.wheels]]
+name = "docstring_to_markdown-0.17-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/56/7b/af3d0da15bed3a8665419bb3a630585756920f4ad67abfdfef26240ebcc0/docstring_to_markdown-0.17-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fd7d5094aa83943bf5f9e1a13701866b7c452eac19765380dead666e36d3711c"
+
+[[packages]]
+name = "docutils"
+version = "0.21.2"
+
+[[packages.wheels]]
+name = "docutils-0.21.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"
+
+[[packages]]
+name = "duckdb"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "duckdb-1.3.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/ab/e9/f83285b0cb3729f24321a038f272490dfb76ca531b7cef832037b7bd077c/duckdb-1.3.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "fbdfc1c0b83b90f780ae74038187ee696bb56ab727a289752372d7ec42dda65b"
+
+[[packages]]
+name = "entrypoints"
+version = "0.4"
+
+[[packages.wheels]]
+name = "entrypoints-0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/35/a8/365059bbcd4572cbc41de17fd5b682be5868b218c3c5479071865cab9078/entrypoints-0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"
+
+[[packages]]
+name = "et-xmlfile"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "et_xmlfile-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"
+
+[[packages]]
+name = "eval-type-backport"
+version = "0.2.2"
+
+[[packages.wheels]]
+name = "eval_type_backport-0.2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a"
+
+[[packages]]
+name = "executing"
+version = "2.2.0"
+
+[[packages.wheels]]
+name = "executing-2.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"
+
+[[packages]]
+name = "faker"
+version = "37.3.0"
+
+[[packages.wheels]]
+name = "faker-37.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ce/99/045b2dae19a01b9fbb23b9971bc04f4ef808e7f3a213d08c81067304a210/faker-37.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "48c94daa16a432f2d2bc803c7ff602509699fca228d13e97e379cd860a7e216e"
+
+[[packages]]
+name = "fasta2a"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "fasta2a-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7a/df/dd967535662ecc9e101a7d6c0c643a055aabc3de47411c31c1dd624356c8/fasta2a-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8b855b36f29fde6dcb79ad55be337a8165381b679bec829913009c55581e284e"
+
+[[packages]]
+name = "fastapi"
+version = "0.115.12"
+
+[[packages.wheels]]
+name = "fastapi-0.115.12-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d"
+
+[[packages]]
+name = "fastavro"
+version = "1.11.1"
+
+[[packages.wheels]]
+name = "fastavro-1.11.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b8/51/38cbe243d5facccab40fc43a4c17db264c261be955ce003803d25f0da2c3/fastavro-1.11.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "cde7ed91b52ff21f0f9f157329760ba7251508ca3e9618af3ffdac986d9faaa2"
+
+[[packages]]
+name = "fastjsonschema"
+version = "2.21.1"
+
+[[packages.wheels]]
+name = "fastjsonschema-2.21.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"
+
+[[packages]]
+name = "filelock"
+version = "3.18.0"
+
+[[packages.wheels]]
+name = "filelock-3.18.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"
+
+[[packages]]
+name = "flake8"
+version = "7.1.1"
+
+[[packages.wheels]]
+name = "flake8-7.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d9/42/65004373ac4617464f35ed15931b30d764f53cdd30cc78d5aea349c8c050/flake8-7.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"
+
+[[packages]]
+name = "flask"
+version = "3.1.1"
+
+[[packages.wheels]]
+name = "flask-3.1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c"
+
+[[packages]]
+name = "flatbuffers"
+version = "25.2.10"
+
+[[packages.wheels]]
+name = "flatbuffers-25.2.10-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b8/25/155f9f080d5e4bc0082edfda032ea2bc2b8fab3f4d25d46c1e9dd22a1a89/flatbuffers-25.2.10-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ebba5f4d5ea615af3f7fd70fc310636fbb2bbd1f566ac0a23d98dd412de50051"
+
+[[packages]]
+name = "flexcache"
+version = "0.3"
+
+[[packages.wheels]]
+name = "flexcache-0.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32"
+
+[[packages]]
+name = "flexparser"
+version = "0.4"
+
+[[packages.wheels]]
+name = "flexparser-0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846"
+
+[[packages]]
+name = "flit"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "flit-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f5/82/ce1d3bb380b227e26e517655d1de7b32a72aad61fa21ff9bd91a2e2db6ee/flit-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2b4e7171dc22881fa6adc2dbf083e5ecc72520be3cd7587d2a803da94d6ef431"
+
+[[packages]]
+name = "flit-core"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "flit_core-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f2/65/b6ba90634c984a4fcc02c7e3afe523fef500c4980fec67cc27536ee50acf/flit_core-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e7a0304069ea895172e3c7bb703292e992c5d1555dd1233ab7b5621b5b69e62c"
+
+[[packages]]
+name = "folium"
+version = "0.19.5"
+
+[[packages.wheels]]
+name = "folium-0.19.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/81/4d/bcbee0676dc06f0b014a030cb928e158c96daafb872a01ddee7e60a8c998/folium-0.19.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4333fb3e6f3e9eedb231615d22c6d7df20aea5829554bd6908675865a37803b3"
+
+[[packages]]
+name = "fonttools"
+version = "4.58.5"
+
+[[packages.wheels]]
+name = "fonttools-4.58.5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/71/a3/21e921b16cb9c029d3308e0cb79c9a937e9ff1fc1ee28c2419f0957b9e7c/fonttools-4.58.5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bca61b14031a4b7dc87e14bf6ca34c275f8e4b9f7a37bc2fe746b532a924cf30"
+
+[[packages]]
+name = "fqdn"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "fqdn-1.5.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"
+
+[[packages]]
+name = "frozenlist"
+version = "1.7.0"
+
+[[packages.wheels]]
+name = "frozenlist-1.7.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba"
+
+[[packages]]
+name = "fsspec"
+version = "2025.5.1"
+
+[[packages.wheels]]
+name = "fsspec-2025.5.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bb/61/78c7b3851add1481b048b5fdc29067397a1784e2910592bc81bb3f608635/fsspec-2025.5.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462"
+
+[[packages]]
+name = "fuzzywuzzy"
+version = "0.18.0"
+
+[[packages.wheels]]
+name = "fuzzywuzzy-0.18.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/43/ff/74f23998ad2f93b945c0309f825be92e04e0348e062026998b5eefef4c33/fuzzywuzzy-0.18.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993"
+
+[[packages]]
+name = "geographiclib"
+version = "2.0"
+
+[[packages.wheels]]
+name = "geographiclib-2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/5a/a26132406f1f40cf51ea349a5f11b0a46cec02a2031ff82e391c2537247a/geographiclib-2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6b7225248e45ff7edcee32becc4e0a1504c606ac5ee163a5656d482e0cd38734"
+
+[[packages]]
+name = "geopandas"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "geopandas-1.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c4/64/7d344cfcef5efddf9cf32f59af7f855828e9d74b5f862eddf5bfd9f25323/geopandas-1.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "01e147d9420cc374d26f51fc23716ac307f32b49406e4bd8462c07e82ed1d3d6"
+
+[[packages]]
+name = "geopy"
+version = "2.4.1"
+
+[[packages.wheels]]
+name = "geopy-2.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e5/15/cf2a69ade4b194aa524ac75112d5caac37414b20a3a03e6865dfe0bd1539/geopy-2.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ae8b4bc5c1131820f4d75fce9d4aaaca0c85189b3aa5d64c3dcaf5e3b7b882a7"
+
+[[packages]]
+name = "gitdb"
+version = "4.0.12"
+
+[[packages.wheels]]
+name = "gitdb-4.0.12-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"
+
+[[packages]]
+name = "gitpython"
+version = "3.1.44"
+
+[[packages.wheels]]
+name = "GitPython-3.1.44-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110"
+
+[[packages]]
+name = "google-auth"
+version = "2.40.3"
+
+[[packages.wheels]]
+name = "google_auth-2.40.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca"
+
+[[packages]]
+name = "google-genai"
+version = "1.20.0"
+
+[[packages.wheels]]
+name = "google_genai-1.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b9/b4/08f3ea414060a7e7d4436c08bb22d03dabef74cc05ef13ef8cd846156d5b/google_genai-1.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ccd61d6ebcb14f5c778b817b8010e3955ae4f6ddfeaabf65f42f6d5e3e5a8125"
+
+[[packages]]
+name = "graphene"
+version = "3.4.3"
+
+[[packages.wheels]]
+name = "graphene-3.4.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71"
+
+[[packages]]
+name = "graphql-core"
+version = "3.2.6"
+
+[[packages.wheels]]
+name = "graphql_core-3.2.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ae/4f/7297663840621022bc73c22d7d9d80dbc78b4db6297f764b545cd5dd462d/graphql_core-3.2.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f"
+
+[[packages]]
+name = "graphql-relay"
+version = "3.2.0"
+
+[[packages.wheels]]
+name = "graphql_relay-3.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5"
+
+[[packages]]
+name = "greenlet"
+version = "3.2.3"
+
+[[packages.wheels]]
+name = "greenlet-3.2.3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/27/1a/199f9587e8cb08a0658f9c30f3799244307614148ffe8b1e3aa22f324dea/greenlet-3.2.3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3"
+
+[[packages]]
+name = "griffe"
+version = "1.7.3"
+
+[[packages.wheels]]
+name = "griffe-1.7.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/58/c6/5c20af38c2a57c15d87f7f38bee77d63c1d2a3689f74fefaf35915dd12b2/griffe-1.7.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75"
+
+[[packages]]
+name = "groq"
+version = "0.28.0"
+
+[[packages.wheels]]
+name = "groq-0.28.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ac/24/20fc18d1b3e0883aeb24286ca8f26dc1970561b07d9c4412c84561bdf307/groq-0.28.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c6f86638371c2cba2ca337232e76c8d412e75965ed7e3058d30c9aa5dfe84303"
+
+[[packages]]
+name = "guidata"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "guidata-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/85/d8/8ebcf690f4f7c828ac97630c48799fbde56847ece5ece7ab513532b3e221/guidata-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8cc05220126dfdd562281de9e761b0c279a4112d699bff55d4b17d95d7bfa1d1"
+
+[[packages]]
+name = "h11"
+version = "0.16.0"
+
+[[packages.wheels]]
+name = "h11-0.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"
+
+[[packages]]
+name = "h2"
+version = "4.2.0"
+
+[[packages.wheels]]
+name = "h2-4.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d0/9e/984486f2d0a0bd2b024bf4bc1c62688fcafa9e61991f041fb0e2def4a982/h2-4.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0"
+
+[[packages]]
+name = "h5py"
+version = "3.12.1"
+
+[[packages.wheels]]
+name = "h5py-3.12.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/50/51/0bbf3663062b2eeee78aa51da71e065f8a0a6e3cb950cc7020b4444999e6/h5py-3.12.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "52ab036c6c97055b85b2a242cb540ff9590bacfda0c03dd0cf0661b311f522f8"
+
+[[packages]]
+name = "hatchling"
+version = "1.27.0"
+
+[[packages.wheels]]
+name = "hatchling-1.27.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/08/e7/ae38d7a6dfba0533684e0b2136817d667588ae3ec984c1a4e5df5eb88482/hatchling-1.27.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d3a2f3567c4f926ea39849cdf924c7e99e6686c9c8e288ae1037c8fa2a5d937b"
+
+[[packages]]
+name = "hpack"
+version = "4.1.0"
+
+[[packages.wheels]]
+name = "hpack-4.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496"
+
+[[packages]]
+name = "html5lib"
+version = "1.1"
+
+[[packages.wheels]]
+name = "html5lib-1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6c/dd/a834df6482147d48e225a49515aabc28974ad5a4ca3215c18a882565b028/html5lib-1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"
+
+[[packages]]
+name = "httpcore"
+version = "1.0.9"
+
+[[packages.wheels]]
+name = "httpcore-1.0.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"
+
+[[packages]]
+name = "httpie"
+version = "3.2.4"
+
+[[packages.wheels]]
+name = "httpie-3.2.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/03/b6/39bcf01e1185882f34bc9fb77d1fb4a27911a55f60ab407de34abc8a2347/httpie-3.2.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4bd0435cc4b9bca59501bc65089de96f3e93b393803f32a81951db62050ebf0b"
+
+[[packages]]
+name = "httpx"
+version = "0.28.1"
+
+[[packages.wheels]]
+name = "httpx-0.28.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"
+
+[[packages]]
+name = "httpx-sse"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "httpx_sse-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"
+
+[[packages]]
+name = "huggingface-hub"
+version = "0.34.4"
+
+[[packages.wheels]]
+name = "huggingface_hub-0.34.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a"
+
+[[packages]]
+name = "humanfriendly"
+version = "10.0"
+
+[[packages.wheels]]
+name = "humanfriendly-10.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"
+
+[[packages]]
+name = "hupper"
+version = "1.12.1"
+
+[[packages.wheels]]
+name = "hupper-1.12.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e872b959f09d90be5fb615bd2e62de89a0b57efc037bdf9637fb09cdf8552b19"
+
+[[packages]]
+name = "hypercorn"
+version = "0.17.3"
+
+[[packages.wheels]]
+name = "hypercorn-0.17.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0e/3b/dfa13a8d96aa24e40ea74a975a9906cfdc2ab2f4e3b498862a57052f04eb/hypercorn-0.17.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547"
+
+[[packages]]
+name = "hyperframe"
+version = "6.1.0"
+
+[[packages.wheels]]
+name = "hyperframe-6.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5"
+
+[[packages]]
+name = "hypothesis"
+version = "6.135.4"
+
+[[packages.wheels]]
+name = "hypothesis-6.135.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/d4/25b3a9f35199eb1904967ca3e6db4afd636911fa39695760b0afac84f38a/hypothesis-6.135.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6a3b13ce35d43e14aaf6a6ca4cc411e5342be5d05b77977499d07cf6a61e6e71"
+
+[[packages]]
+name = "id"
+version = "1.5.0"
+
+[[packages.wheels]]
+name = "id-1.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/cb/18326d2d89ad3b0dd143da971e77afd1e6ca6674f1b1c3df4b6bec6279fc/id-1.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"
+
+[[packages]]
+name = "idna"
+version = "3.10"
+
+[[packages.wheels]]
+name = "idna-3.10-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
+
+[[packages]]
+name = "imageio"
+version = "2.37.0"
+
+[[packages.wheels]]
+name = "imageio-2.37.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cb/bd/b394387b598ed84d8d0fa90611a90bee0adc2021820ad5729f7ced74a8e2/imageio-2.37.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed"
+
+[[packages]]
+name = "imagesize"
+version = "1.4.1"
+
+[[packages.wheels]]
+name = "imagesize-1.4.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"
+
+[[packages]]
+name = "importlib-metadata"
+version = "8.7.0"
+
+[[packages.wheels]]
+name = "importlib_metadata-8.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"
+
+[[packages]]
+name = "inflection"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "inflection-0.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"
+
+[[packages]]
+name = "iniconfig"
+version = "2.1.0"
+
+[[packages.wheels]]
+name = "iniconfig-2.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"
+
+[[packages]]
+name = "intervaltree"
+version = "3.1.0"
+
+[packages.sdist]
+name = "intervaltree-3.1.0.tar.gz"
+url = "https://files.pythonhosted.org/packages/50/fb/396d568039d21344639db96d940d40eb62befe704ef849b27949ded5c3bb/intervaltree-3.1.0.tar.gz"
+
+[packages.sdist.hashes]
+sha256 = "902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d"
+
+[[packages]]
+name = "ipycanvas"
+version = "0.13.3"
+
+[[packages.wheels]]
+name = "ipycanvas-0.13.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/fc/e3867e413adbfede3a9c372ec015416ccb0a6493659db5812eeec447a73b/ipycanvas-0.13.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d37adb2f45d2fef1c3d33c69a0518055694d87827b2f577f3c426d7712f75daa"
+
+[[packages]]
+name = "ipykernel"
+version = "6.29.5"
+
+[[packages.wheels]]
+name = "ipykernel-6.29.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"
+
+[[packages]]
+name = "ipyleaflet"
+version = "0.20.0"
+
+[[packages.wheels]]
+name = "ipyleaflet-0.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/49/69/e9858f2c0b99bf9f036348d1c84b8026f438bb6875effe6a9bcd9883dada/ipyleaflet-0.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b4c20ddc0b17d68e226cd3367ca2215a4db7e2b14374468c0eeaa54b53e4d173"
+
+[[packages]]
+name = "ipympl"
+version = "0.9.7"
+
+[[packages.wheels]]
+name = "ipympl-0.9.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/86/6b/21c62f1b2b5e18c6553f7364487dfdf7eb7952b1000a1b7863c1f97819e9/ipympl-0.9.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3698ee7eaa0b047a7603517d7aa1b71b32118a5f51754cab45ec5d994f67208f"
+
+[[packages]]
+name = "ipython"
+version = "8.37.0"
+
+[[packages.wheels]]
+name = "ipython-8.37.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"
+
+[[packages]]
+name = "ipython-genutils"
+version = "0.2.0"
+
+[[packages.wheels]]
+name = "ipython_genutils-0.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fa/bc/9bd3b5c2b4774d5f33b2d544f1460be9df7df2fe42f352135381c347c69a/ipython_genutils-0.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"
+
+[[packages]]
+name = "ipython-sql"
+version = "0.5.0"
+
+[[packages.wheels]]
+name = "ipython_sql-0.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/30/8f/9e50fa53ffc371483f9d1b90c1175b706d28a2e978e90a8894035af01905/ipython_sql-0.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "61b46ecffb956f62dbc17b5744cf70c649104c8db9afd821aa39b31f7cbb5d5b"
+
+[[packages]]
+name = "ipywidgets"
+version = "8.1.7"
+
+[[packages.wheels]]
+name = "ipywidgets-8.1.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb"
+
+[[packages]]
+name = "isoduration"
+version = "20.11.0"
+
+[[packages.wheels]]
+name = "isoduration-20.11.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"
+
+[[packages]]
+name = "isort"
+version = "6.0.1"
+
+[[packages.wheels]]
+name = "isort-6.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"
+
+[[packages]]
+name = "itsdangerous"
+version = "2.2.0"
+
+[[packages.wheels]]
+name = "itsdangerous-2.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"
+
+[[packages]]
+name = "janus"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "janus-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/68/34/65604740edcb20e1bda6a890348ed7d282e7dd23aa00401cbe36fd0edbd9/janus-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7e6449d34eab04cd016befbd7d8c0d8acaaaab67cb59e076a69149f9031745f9"
+
+[[packages]]
+name = "jaraco-classes"
+version = "3.4.0"
+
+[[packages.wheels]]
+name = "jaraco.classes-3.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"
+
+[[packages]]
+name = "jaraco-context"
+version = "6.0.1"
+
+[[packages.wheels]]
+name = "jaraco.context-6.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"
+
+[[packages]]
+name = "jaraco-functools"
+version = "4.2.1"
+
+[[packages.wheels]]
+name = "jaraco_functools-4.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f3/fd/179a20f832824514df39a90bb0e5372b314fea99f217f5ab942b10a8a4e8/jaraco_functools-4.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e"
+
+[[packages]]
+name = "jedi"
+version = "0.19.2"
+
+[[packages.wheels]]
+name = "jedi-0.19.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"
+
+[[packages]]
+name = "jellyfish"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "jellyfish-1.2.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/40/aa/332fd282668a353570bdad56d65f526bc28ab73da1a3dd99e670af687186/jellyfish-1.2.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "c8089e918ddb1abae946e92d053f646a7f686d0d051ef69cdfaa28b37352bbdf"
+
+[[packages]]
+name = "jinja2"
+version = "3.1.6"
+
+[[packages.wheels]]
+name = "jinja2-3.1.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"
+
+[[packages]]
+name = "jiter"
+version = "0.10.0"
+
+[[packages.wheels]]
+name = "jiter-0.10.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7e/07/1c96b623128bcb913706e294adb5f768fb7baf8db5e1338ce7b4ee8c78ef/jiter-0.10.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "75f9eb72ecb640619c29bf714e78c9c46c9c4eaafd644bf78577ede459f330d4"
+
+[[packages]]
+name = "joblib"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "joblib-1.5.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a"
+
+[[packages]]
+name = "json5"
+version = "0.12.0"
+
+[[packages.wheels]]
+name = "json5-0.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db"
+
+[[packages]]
+name = "jsonpatch"
+version = "1.33"
+
+[[packages.wheels]]
+name = "jsonpatch-1.33-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"
+
+[[packages]]
+name = "jsonpointer"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "jsonpointer-3.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"
+
+[[packages]]
+name = "jsonschema"
+version = "4.24.0"
+
+[[packages.wheels]]
+name = "jsonschema-4.24.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d"
+
+[[packages]]
+name = "jsonschema-specifications"
+version = "2025.4.1"
+
+[[packages.wheels]]
+name = "jsonschema_specifications-2025.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"
+
+[[packages]]
+name = "julia"
+version = "0.6.2"
+
+[[packages.wheels]]
+name = "julia-0.6.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/af/2e9a1a996f32b34249582392bb419cf8983b627a1d31412acbe9d6dea5b0/julia-0.6.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "90752f71376fdb9919439d20496c2dab24486dfa4fe8a831d6dd14a1bcbc04d1"
+
+[[packages]]
+name = "jupyter"
+version = "1.1.1"
+
+[[packages.wheels]]
+name = "jupyter-1.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83"
+
+[[packages]]
+name = "jupyter-bokeh"
+version = "4.0.5"
+
+[[packages.wheels]]
+name = "jupyter_bokeh-4.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/47/78/33b2294aad62e5f95b89a89379c5995c2bd978018387ef8bec79f6dc272c/jupyter_bokeh-4.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1110076c14c779071cf492646a1a871aefa8a477261e4721327a666e65df1a2c"
+
+[[packages]]
+name = "jupyter-client"
+version = "8.6.3"
+
+[[packages.wheels]]
+name = "jupyter_client-8.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"
+
+[[packages]]
+name = "jupyter-console"
+version = "6.6.3"
+
+[[packages.wheels]]
+name = "jupyter_console-6.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485"
+
+[[packages]]
+name = "jupyter-core"
+version = "5.8.1"
+
+[[packages.wheels]]
+name = "jupyter_core-5.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0"
+
+[[packages]]
+name = "jupyter-events"
+version = "0.12.0"
+
+[[packages.wheels]]
+name = "jupyter_events-0.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb"
+
+[[packages]]
+name = "jupyter-leaflet"
+version = "0.20.0"
+
+[[packages.wheels]]
+name = "jupyter_leaflet-0.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/16/95/ffe543060eb3b1570d78c3f2c1948c640a6758ff5c6479c27e474819115b/jupyter_leaflet-0.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2e27ce83647316424f04845e3a6af35e1ee44c177c318a145646b11f4afe0764"
+
+[[packages]]
+name = "jupyter-lsp"
+version = "2.2.5"
+
+[[packages.wheels]]
+name = "jupyter_lsp-2.2.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da"
+
+[[packages]]
+name = "jupyter-server"
+version = "2.16.0"
+
+[[packages.wheels]]
+name = "jupyter_server-2.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/46/1f/5ebbced977171d09a7b0c08a285ff9a20aafb9c51bde07e52349ff1ddd71/jupyter_server-2.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3d8db5be3bc64403b1c65b400a1d7f4647a5ce743f3b20dbdefe8ddb7b55af9e"
+
+[[packages]]
+name = "jupyter-server-terminals"
+version = "0.5.3"
+
+[[packages.wheels]]
+name = "jupyter_server_terminals-0.5.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"
+
+[[packages]]
+name = "jupyterlab"
+version = "4.4.4"
+
+[[packages.wheels]]
+name = "jupyterlab-4.4.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f8/82/66910ce0995dbfdb33609f41c99fe32ce483b9624a3e7d672af14ff63b9f/jupyterlab-4.4.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd"
+
+[[packages]]
+name = "jupyterlab-pygments"
+version = "0.3.0"
+
+[[packages.wheels]]
+name = "jupyterlab_pygments-0.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"
+
+[[packages]]
+name = "jupyterlab-server"
+version = "2.27.3"
+
+[[packages.wheels]]
+name = "jupyterlab_server-2.27.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4"
+
+[[packages]]
+name = "jupyterlab-widgets"
+version = "3.0.15"
+
+[[packages.wheels]]
+name = "jupyterlab_widgets-3.0.15-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c"
+
+[[packages]]
+name = "keras"
+version = "3.11.3"
+
+[[packages.wheels]]
+name = "keras-3.11.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/94/5b/4c778cc921ce4b864b238f63f8e3ff6e954ab19b80c9fa680593ad8093d4/keras-3.11.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f484f050e05ee400455b05ec8c36ed35edc34de94256b6073f56cfe68f65491f"
+
+[[packages]]
+name = "keyring"
+version = "25.6.0"
+
+[[packages.wheels]]
+name = "keyring-25.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"
+
+[[packages]]
+name = "kiwisolver"
+version = "1.4.8"
+
+[[packages.wheels]]
+name = "kiwisolver-1.4.8-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2"
+
+[[packages]]
+name = "langchain"
+version = "0.3.27"
+
+[[packages.wheels]]
+name = "langchain-0.3.27-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f6/d5/4861816a95b2f6993f1360cfb605aacb015506ee2090433a71de9cca8477/langchain-0.3.27-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7b20c4f338826acb148d885b20a73a16e410ede9ee4f19bb02011852d5f98798"
+
+[[packages]]
+name = "langchain-core"
+version = "0.3.72"
+
+[[packages.wheels]]
+name = "langchain_core-0.3.72-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6e/7d/9f75023c478e3b854d67da31d721e39f0eb30ae969ec6e755430cb1c0fb5/langchain_core-0.3.72-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9fa15d390600eb6b6544397a7aa84be9564939b6adf7a2b091179ea30405b240"
+
+[[packages]]
+name = "langchain-text-splitters"
+version = "0.3.9"
+
+[[packages.wheels]]
+name = "langchain_text_splitters-0.3.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/52/7638394b88bc15083fd2c3752a843784d9d2d110d68fed6437c8607fb749/langchain_text_splitters-0.3.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cee0bb816211584ea79cc79927317c358543f40404bcfdd69e69ba3ccde54401"
+
+[[packages]]
+name = "langsmith"
+version = "0.4.8"
+
+[[packages.wheels]]
+name = "langsmith-0.4.8-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/19/4f/481324462c44ce21443b833ad73ee51117031d41c16fec06cddbb7495b26/langsmith-0.4.8-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ca2f6024ab9d2cd4d091b2e5b58a5d2cb0c354a0c84fe214145a89ad450abae0"
+
+[[packages]]
+name = "lazy-loader"
+version = "0.4"
+
+[[packages.wheels]]
+name = "lazy_loader-0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc"
+
+[[packages]]
+name = "llvmlite"
+version = "0.44.0"
+
+[[packages.wheels]]
+name = "llvmlite-0.44.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/d0/81/e66fc86539293282fd9cb7c9417438e897f369e79ffb62e1ae5e5154d4dd/llvmlite-0.44.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "2fb7c4f2fb86cbae6dca3db9ab203eeea0e22d73b99bc2341cdf9de93612e930"
+
+[[packages]]
+name = "lmfit"
+version = "1.3.3"
+
+[[packages.wheels]]
+name = "lmfit-1.3.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6a/e1/d5aeb89530550c7e797d3528225fa31012490e79c9df5cf72a0f07cc66d3/lmfit-1.3.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a9e9ec7d0d0ec962cc6c078ad1ec6c8311d3ac0e5f0947a00a91f5509dacc2b2"
+
+[[packages]]
+name = "locket"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "locket-1.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b6c819a722f7b6bd955b80781788e4a66a55628b858d347536b7e81325a3a5e3"
+
+[[packages]]
+name = "logfire-api"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "logfire_api-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/97/c6/210bb1da7119af155276046c18ceff29867dfe9ea4bcb7d03397b28bd1cd/logfire_api-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fc092c2dcb24c8462ba776f3b0c2183f82e1cd55f86e29b38cf21a048e66a17d"
+
+[[packages]]
+name = "lxml"
+version = "6.0.0"
+
+[[packages.wheels]]
+name = "lxml-6.0.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f4/87/6456b9541d186ee7d4cb53bf1b9a0d7f3b1068532676940fdd594ac90865/lxml-6.0.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e"
+
+[[packages]]
+name = "mako"
+version = "1.3.10"
+
+[[packages.wheels]]
+name = "mako-1.3.10-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"
+
+[[packages]]
+name = "markdown"
+version = "3.7"
+
+[[packages.wheels]]
+name = "Markdown-3.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"
+
+[[packages]]
+name = "markdown-it-py"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "markdown_it_py-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"
+
+[[packages]]
+name = "markupsafe"
+version = "3.0.2"
+
+[[packages.wheels]]
+name = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"
+
+[[packages]]
+name = "matplotlib"
+version = "3.10.5"
+
+[[packages.wheels]]
+name = "matplotlib-3.10.5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/36/c2/24302e93ff431b8f4173ee1dd88976c8d80483cadbc5d3d777cef47b3a1c/matplotlib-3.10.5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "07442d2692c9bd1cceaa4afb4bbe5b57b98a7599de4dabfcca92d3eea70f9ebe"
+
+[[packages]]
+name = "matplotlib-inline"
+version = "0.1.7"
+
+[[packages.wheels]]
+name = "matplotlib_inline-0.1.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"
+
+[[packages]]
+name = "maturin"
+version = "1.9.0"
+
+[[packages.wheels]]
+name = "maturin-1.9.0-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/0e/44/b3236b2a3f6d26600cb3c81535c06c80fd80cbcdcf893648d8bb8660edbe/maturin-1.9.0-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "fb9796c1893d1e3cd9da9325ef3c63d54a5b0fe6183ddae4954b10c64a1ae5e3"
+
+[[packages]]
+name = "mccabe"
+version = "0.7.0"
+
+[[packages.wheels]]
+name = "mccabe-0.7.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
+
+[[packages]]
+name = "mcp"
+version = "1.9.3"
+
+[[packages.wheels]]
+name = "mcp-1.9.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/79/45/823ad05504bea55cb0feb7470387f151252127ad5c72f8882e8fe6cf5c0e/mcp-1.9.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "69b0136d1ac9927402ed4cf221d4b8ff875e7132b0b06edd446448766f34f9b9"
+
+[[packages]]
+name = "mdurl"
+version = "0.1.2"
+
+[[packages.wheels]]
+name = "mdurl-0.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"
+
+[[packages]]
+name = "mercantile"
+version = "1.2.1"
+
+[[packages.wheels]]
+name = "mercantile-1.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b2/d6/de0cc74f8d36976aeca0dd2e9cbf711882ff8e177495115fd82459afdc4d/mercantile-1.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "30f457a73ee88261aab787b7069d85961a5703bb09dc57a170190bc042cd023f"
+
+[[packages]]
+name = "mergedeep"
+version = "1.3.4"
+
+[[packages.wheels]]
+name = "mergedeep-1.3.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"
+
+[[packages]]
+name = "missingno"
+version = "0.5.2"
+
+[[packages.wheels]]
+name = "missingno-0.5.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/22/cd5cf999af21c2f97486622c551ac3d07361ced8125121e907f588ff5f24/missingno-0.5.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "55782621ce09ba0f0a1d08e5bd6d6fe1946469fb03951fadf7d209911ca5b072"
+
+[[packages]]
+name = "mistralai"
+version = "1.9.3"
+
+[[packages.wheels]]
+name = "mistralai-1.9.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/9a/0c48706c646b0391b798f8568f2b1545e54d345805e988003c10450b7b4c/mistralai-1.9.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "962445e7cebadcbfbcd1daf973e853a832dcf7aba6320468fcf7e2cf5f943aec"
+
+[[packages]]
+name = "mistune"
+version = "3.1.3"
+
+[[packages.wheels]]
+name = "mistune-3.1.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/01/4d/23c4e4f09da849e127e9f123241946c23c1e30f45a88366879e064211815/mistune-3.1.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9"
+
+[[packages]]
+name = "mizani"
+version = "0.11.4"
+
+[[packages.wheels]]
+name = "mizani-0.11.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/11/f3777ad46c5d92e3ead121c22ea45fafb6c3b2c1edca0c0c6494969c125c/mizani-0.11.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5b6271dc3da2c88694dca2e0e0a7e1879f0e2fb046c789776f54d090a5243735"
+
+[[packages]]
+name = "ml-dtypes"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "ml_dtypes-0.5.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/da/8a/a2b9375c94077e5a488a624a195621407846f504068ce22ccf805c674156/ml_dtypes-0.5.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "fd918d4e6a4e0c110e2e05be7a7814d10dc1b95872accbf6512b80a109b71ae1"
+
+[[packages]]
+name = "mlxtend"
+version = "0.23.3"
+
+[[packages.wheels]]
+name = "mlxtend-0.23.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/92/5c322336a0991949a1e91f6acd7e04f7e05b0fb6252a3f00fcdc0cb5e97d/mlxtend-0.23.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f9fec721c4121be87dac00e513456dde5bf56b7427750719c0a291cd58b6538e"
+
+[[packages]]
+name = "more-itertools"
+version = "10.7.0"
+
+[[packages.wheels]]
+name = "more_itertools-10.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e"
+
+[[packages]]
+name = "mpld3"
+version = "0.5.10"
+
+[[packages.wheels]]
+name = "mpld3-0.5.10-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/95/6a/e3691bcc47485f38b09853207c928130571821d187cf174eed5418d45e82/mpld3-0.5.10-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1"
+
+[[packages]]
+name = "mpmath"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "mpmath-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"
+
+[[packages]]
+name = "msal"
+version = "1.32.3"
+
+[[packages.wheels]]
+name = "msal-1.32.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/bf/81516b9aac7fd867709984d08eb4db1d2e3fe1df795c8e442cde9b568962/msal-1.32.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b2798db57760b1961b142f027ffb7c8169536bf77316e99a0df5c4aaebb11569"
+
+[[packages]]
+name = "msal-extensions"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "msal_extensions-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5e/75/bd9b7bb966668920f06b200e84454c8f3566b102183bc55c5473d96cb2b9/msal_extensions-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca"
+
+[[packages]]
+name = "msgpack"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "msgpack-1.1.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b6/bc/8bd826dd03e022153bfa1766dcdec4976d6c818865ed54223d71f07862b3/msgpack-1.1.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"
+
+[[packages]]
+name = "multidict"
+version = "6.4.4"
+
+[[packages.wheels]]
+name = "multidict-6.4.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373"
+
+[[packages]]
+name = "mypy"
+version = "1.16.1"
+
+[[packages.wheels]]
+name = "mypy-1.16.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/5a/fd/d486a0827a1c597b3b48b1bdef47228a6e9ee8102ab8c28f944cb83b65dc/mypy-1.16.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee"
+
+[[packages]]
+name = "mypy-extensions"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "mypy_extensions-1.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"
+
+[[packages]]
+name = "namex"
+version = "0.1.0"
+
+[[packages.wheels]]
+name = "namex-0.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b2/bc/465daf1de06409cdd4532082806770ee0d8d7df434da79c76564d0f69741/namex-0.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e2012a474502f1e2251267062aae3114611f07df4224b6e06334c57b0f2ce87c"
+
+[[packages]]
+name = "narwhals"
+version = "2.0.1"
+
+[[packages.wheels]]
+name = "narwhals-2.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/26/43caf834e47c63883a5eddc02893b7fdbe6a0a4508ff6dc401907f3cc085/narwhals-2.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "837457e36a2ba1710c881fb69e1f79ce44fb81728c92ac378f70892a53af8ddb"
+
+[[packages]]
+name = "nbclient"
+version = "0.10.2"
+
+[[packages.wheels]]
+name = "nbclient-0.10.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d"
+
+[[packages]]
+name = "nbconvert"
+version = "7.16.6"
+
+[[packages.wheels]]
+name = "nbconvert-7.16.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b"
+
+[[packages]]
+name = "nbformat"
+version = "5.10.4"
+
+[[packages.wheels]]
+name = "nbformat-5.10.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"
+
+[[packages]]
+name = "nest-asyncio"
+version = "1.6.0"
+
+[[packages.wheels]]
+name = "nest_asyncio-1.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"
+
+[[packages]]
+name = "networkx"
+version = "3.5"
+
+[[packages.wheels]]
+name = "networkx-3.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec"
+
+[[packages]]
+name = "nh3"
+version = "0.2.21"
+
+[[packages.wheels]]
+name = "nh3-0.2.21-cp38-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/23/fc/8ce756c032c70ae3dd1d48a3552577a325475af2a2f629604b44f571165c/nh3-0.2.21-cp38-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629"
+
+[[packages]]
+name = "nltk"
+version = "3.9.1"
+
+[[packages.wheels]]
+name = "nltk-3.9.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4d/66/7d9e26593edda06e8cb531874633f7c2372279c3b0f46235539fe546df8b/nltk-3.9.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1"
+
+[[packages]]
+name = "notebook"
+version = "7.4.2"
+
+[[packages.wheels]]
+name = "notebook-7.4.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/1e/16/d3c36a0b1f6dfcf218add8eaf803bf0473ff50681ac4d51acb7ba02bce34/notebook-7.4.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9ccef602721aaa5530852e3064710b8ae5415c4e2ce26f8896d0433222755259"
+
+[[packages]]
+name = "notebook-shim"
+version = "0.2.4"
+
+[[packages.wheels]]
+name = "notebook_shim-0.2.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef"
+
+[[packages]]
+name = "numba"
+version = "0.61.2"
+
+[[packages.wheels]]
+name = "numba-0.61.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/af/a4/6d3a0f2d3989e62a18749e1e9913d5fa4910bbb3e3311a035baea6caf26d/numba-0.61.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "59321215e2e0ac5fa928a8020ab00b8e57cda8a97384963ac0dfa4d4e6aa54e7"
+
+[[packages]]
+name = "numpy"
+version = "2.2.6"
+
+[[packages.wheels]]
+name = "numpy-2.2.6-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"
+
+[[packages]]
+name = "numpydoc"
+version = "1.8.0"
+
+[[packages.wheels]]
+name = "numpydoc-1.8.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6c/45/56d99ba9366476cd8548527667f01869279cedb9e66b28eb4dfb27701679/numpydoc-1.8.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72024c7fd5e17375dec3608a27c03303e8ad00c81292667955c6fea7a3ccf541"
+
+[[packages]]
+name = "onnxruntime"
+version = "1.22.1"
+
+[[packages.wheels]]
+name = "onnxruntime-1.22.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/4c/06/9c765e66ad32a7e709ce4cb6b95d7eaa9cb4d92a6e11ea97c20ffecaf765/onnxruntime-1.22.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "70980d729145a36a05f74b573435531f55ef9503bcda81fc6c3d6b9306199982"
+
+[[packages]]
+name = "openai"
+version = "1.101.0"
+
+[[packages.wheels]]
+name = "openai-1.101.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c8/a6/0e39baa335bbd1c66c7e0a41dbbec10c5a15ab95c1344e7f7beb28eee65a/openai-1.101.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6539a446cce154f8d9fb42757acdfd3ed9357ab0d34fcac11096c461da87133b"
+
+[[packages]]
+name = "opencv-python"
+version = "4.11.0.86"
+
+[[packages.wheels]]
+name = "opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a4/7d/f1c30a92854540bf789e9cd5dde7ef49bbe63f855b85a2e6b3db8135c591/opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec"
+
+[[packages]]
+name = "openpyxl"
+version = "3.1.5"
+
+[[packages.wheels]]
+name = "openpyxl-3.1.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"
+
+[[packages]]
+name = "opentelemetry-api"
+version = "1.34.1"
+
+[[packages.wheels]]
+name = "opentelemetry_api-1.34.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/3a/2ba85557e8dc024c0842ad22c570418dc02c36cbd1ab4b832a93edf071b8/opentelemetry_api-1.34.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c"
+
+[[packages]]
+name = "optree"
+version = "0.14.1"
+
+[[packages.wheels]]
+name = "optree-0.14.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/90/43/93aa65f56b857b8364e76d76eb188a4a6912ed305374b90f9ba30dcf0de9/optree-0.14.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "25ea23fc6d6c0fa7dcf85afcfe10b43ed4fdf0e9d958a3677cd27fcdf0ca17d6"
+
+[[packages]]
+name = "optuna"
+version = "4.2.1"
+
+[[packages.wheels]]
+name = "optuna-4.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/28/09/c4d329f7969443cdd4d482048ca406b6f61cda3c8e99ace71feaec7c8734/optuna-4.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6d38199013441d3f70fac27136e05c0188c5f4ec3848db708ac311cbdeb30dbf"
+
+[[packages]]
+name = "orjson"
+version = "3.10.18"
+
+[[packages.wheels]]
+name = "orjson-3.10.18-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/4b/03/c75c6ad46be41c16f4cfe0352a2d1450546f3c09ad2c9d341110cd87b025/orjson-3.10.18-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52"
+
+[[packages]]
+name = "osqp"
+version = "0.6.7.post3"
+
+[[packages.wheels]]
+name = "osqp-0.6.7.post3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/4b/0a/acd48ad432ccf2538972805095108801a3b29a2433b48bd3a34e640df1e4/osqp-0.6.7.post3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "acb219e941f5248da5de3ee9b70e6a5aaddf5f3989dffd1d4c03b0f7b1dfa17b"
+
+[[packages]]
+name = "outcome"
+version = "1.3.0.post0"
+
+[[packages.wheels]]
+name = "outcome-1.3.0.post0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b"
+
+[[packages]]
+name = "overrides"
+version = "7.7.0"
+
+[[packages.wheels]]
+name = "overrides-7.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49"
+
+[[packages]]
+name = "packaging"
+version = "25.0"
+
+[[packages.wheels]]
+name = "packaging-25.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"
+
+[[packages]]
+name = "pandas"
+version = "2.3.1"
+
+[[packages.wheels]]
+name = "pandas-2.3.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b2/c0/54415af59db5cdd86a3d3bf79863e8cc3fa9ed265f0745254061ac09d5f2/pandas-2.3.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956"
+
+[[packages]]
+name = "pandocfilters"
+version = "1.5.1"
+
+[[packages.wheels]]
+name = "pandocfilters-1.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"
+
+[[packages]]
+name = "papermill"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "papermill-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/55/83ce641bc61a70cc0721af6f50154ecaaccedfbdbc27366c1755a2a34972/papermill-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0f09da6ef709f3f14dde77cb1af052d05b14019189869affff374c9e612f2dd5"
+
+[[packages]]
+name = "parso"
+version = "0.8.4"
+
+[[packages.wheels]]
+name = "parso-0.8.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"
+
+[[packages]]
+name = "partd"
+version = "1.4.2"
+
+[[packages.wheels]]
+name = "partd-1.4.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "978e4ac767ec4ba5b86c6eaa52e5a2a3bc748a2ca839e8cc798f1cc6ce6efb0f"
+
+[[packages]]
+name = "pathspec"
+version = "0.12.1"
+
+[[packages.wheels]]
+name = "pathspec-0.12.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"
+
+[[packages]]
+name = "patsy"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "patsy-1.0.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/87/2b/b50d3d08ea0fc419c183a84210571eba005328efa62b6b98bc28e9ead32a/patsy-1.0.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "751fb38f9e97e62312e921a1954b81e1bb2bcda4f5eeabaf94db251ee791509c"
+
+[[packages]]
+name = "pep8"
+version = "1.7.1"
+
+[[packages.wheels]]
+name = "pep8-1.7.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/42/3f/669429ce58de2c22d8d2c542752e137ec4b9885fff398d3eceb1a7f5acb4/pep8-1.7.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee"
+
+[[packages]]
+name = "pexpect"
+version = "4.9.0"
+
+[[packages.wheels]]
+name = "pexpect-4.9.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"
+
+[[packages]]
+name = "pg8000"
+version = "1.31.2"
+
+[[packages.wheels]]
+name = "pg8000-1.31.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/09/a0/2b30d52017c4ced8fc107386666ea7573954eb708bf66121f0229df05d41/pg8000-1.31.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "436c771ede71af4d4c22ba867a30add0bc5c942d7ab27fadbb6934a487ecc8f6"
+
+[[packages]]
+name = "pickleshare"
+version = "0.7.5"
+
+[[packages.wheels]]
+name = "pickleshare-0.7.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9a/41/220f49aaea88bc6fa6cba8d05ecf24676326156c23b991e80b3f2fc24c77/pickleshare-0.7.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"
+
+[[packages]]
+name = "pillow"
+version = "11.3.0"
+
+[[packages.wheels]]
+name = "pillow-11.3.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"
+
+[[packages]]
+name = "pip"
+version = "25.2"
+
+[[packages.wheels]]
+name = "pip-25.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/3f/945ef7ab14dc4f9d7f40288d2df998d1837ee0888ec3659c813487572faa/pip-25.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6d67a2b4e7f14d8b31b8b52648866fa717f45a1eb70e83002f4331d07e953717"
+
+[[packages]]
+name = "platformdirs"
+version = "4.3.7"
+
+[[packages.wheels]]
+name = "platformdirs-4.3.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6d/45/59578566b3275b8fd9157885918fcd0c4d74162928a5310926887b856a51/platformdirs-4.3.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"
+
+[[packages]]
+name = "plotly"
+version = "6.2.0"
+
+[[packages.wheels]]
+name = "plotly-6.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ed/20/f2b7ac96a91cc5f70d81320adad24cc41bf52013508d649b1481db225780/plotly-6.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "32c444d4c940887219cb80738317040363deefdfee4f354498cc0b6dab8978bd"
+
+[[packages]]
+name = "plotnine"
+version = "0.13.6"
+
+[[packages.wheels]]
+name = "plotnine-0.13.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/93/b1/e1c84e68cf24e83c4d251122e04c48840be203dafb4727e738381cdefa74/plotnine-0.13.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4acc1af29fa4e91e726b67d49277e8368f62e1c817f01bf14ecd8ca5e83bfaea"
+
+[[packages]]
+name = "plotpy"
+version = "2.7.4"
+
+[[packages.wheels]]
+name = "plotpy-2.7.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/61/98/9bc8f5a00dd45b53c37292c08ebcf9f94e895838ab2ad295d1c0eec88332/plotpy-2.7.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8dff5fd388048a8d3b4251329a9fe4027920386e0ebcc3c3642f59c432118c29"
+
+[[packages]]
+name = "pluggy"
+version = "1.5.0"
+
+[[packages.wheels]]
+name = "pluggy-1.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"
+
+[[packages]]
+name = "ply"
+version = "3.11"
+
+[[packages.wheels]]
+name = "ply-3.11-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"
+
+[[packages]]
+name = "polars"
+version = "1.32.2"
+
+[[packages.wheels]]
+name = "polars-1.32.2-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/91/58/d2840554ef1c69e06a28ee928bdaa0d6a61af12205ff24c096628f217f99/polars-1.32.2-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "5e1660a584e89e1d60cd89984feca38a695e491a966581fefe8be99c230ea154"
+
+[[packages]]
+name = "prettytable"
+version = "3.16.0"
+
+[[packages.wheels]]
+name = "prettytable-3.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/02/c7/5613524e606ea1688b3bdbf48aa64bafb6d0a4ac3750274c43b6158a390f/prettytable-3.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b5eccfabb82222f5aa46b798ff02a8452cf530a352c31bddfa29be41242863aa"
+
+[[packages]]
+name = "prince"
+version = "0.16.0"
+
+[[packages.wheels]]
+name = "prince-0.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/18/d5/b4480a0f381cbbcfad31f4d118732ab717216857508a730938ee615669a1/prince-0.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7e21a78d4dd06ca3ec526ee714a50b349f26de3fca6b79664150a951b31688f3"
+
+[[packages]]
+name = "priority"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "priority-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"
+
+[[packages]]
+name = "prometheus-client"
+version = "0.21.1"
+
+[[packages.wheels]]
+name = "prometheus_client-0.21.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/c2/ab7d37426c179ceb9aeb109a85cda8948bb269b7561a0be870cc656eefe4/prometheus_client-0.21.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301"
+
+[[packages]]
+name = "prompt-toolkit"
+version = "3.0.51"
+
+[[packages.wheels]]
+name = "prompt_toolkit-3.0.51-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"
+
+[[packages]]
+name = "propcache"
+version = "0.3.1"
+
+[[packages.wheels]]
+name = "propcache-0.3.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a6/2c/a54614d61895ba6dd7ac8f107e2b2a0347259ab29cbf2ecc7b94fa38c4dc/propcache-0.3.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"
+
+[[packages]]
+name = "protobuf"
+version = "6.30.2"
+
+[[packages.wheels]]
+name = "protobuf-6.30.2-cp310-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/97/e9/7b9f1b259d509aef2b833c29a1f3c39185e2bf21c9c1be1cd11c22cb2149/protobuf-6.30.2-cp310-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "7653c99774f73fe6b9301b87da52af0e69783a2e371e8b599b3e9cb4da4b12b9"
+
+[[packages]]
+name = "psutil"
+version = "7.0.0"
+
+[[packages.wheels]]
+name = "psutil-7.0.0-cp37-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"
+
+[[packages]]
+name = "psygnal"
+version = "0.12.0"
+
+[[packages.wheels]]
+name = "psygnal-0.12.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/5e/ae/a3d6815db583b6d05878b3647ea0e2aa21ce6941d03c9d2c6caad1afbcf6/psygnal-0.12.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "d779f20c6977ec9d5b9fece23b4b28bbcf0a7773539a4a176b5527aea5da27c7"
+
+[[packages]]
+name = "ptpython"
+version = "3.0.30"
+
+[[packages.wheels]]
+name = "ptpython-3.0.30-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/05/15/77dfd9a52fa6c87b50232b246df0cfacacc0665c95ebe4a517cc994819f0/ptpython-3.0.30-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bec3045f0285ac817c902ef98d6ece31d3e00a4604ef3fdde07d365c78bde23c"
+
+[[packages]]
+name = "ptyprocess"
+version = "0.7.0"
+
+[[packages.wheels]]
+name = "ptyprocess-0.7.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"
+
+[[packages]]
+name = "pure-eval"
+version = "0.2.3"
+
+[[packages.wheels]]
+name = "pure_eval-0.2.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"
+
+[[packages]]
+name = "pyarrow"
+version = "21.0.0"
+
+[[packages.wheels]]
+name = "pyarrow-21.0.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/01/63/581f2076465e67b23bc5a37d4a2abff8362d389d29d8105832e82c9c811c/pyarrow-21.0.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636"
+
+[[packages]]
+name = "pyasn1"
+version = "0.6.1"
+
+[[packages.wheels]]
+name = "pyasn1-0.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"
+
+[[packages]]
+name = "pyasn1-modules"
+version = "0.4.1"
+
+[[packages.wheels]]
+name = "pyasn1_modules-0.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/77/89/bc88a6711935ba795a679ea6ebee07e128050d6382eaa35a0a47c8032bdc/pyasn1_modules-0.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"
+
+[[packages]]
+name = "pybind11"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "pybind11-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/41/9c/85f50a5476832c3efc67b6d7997808388236ae4754bf53e1749b3bc27577/pybind11-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7c5cac504da5a701b5163f0e6a7ba736c713a096a5378383c5b4b064b753f607"
+
+[[packages]]
+name = "pycodestyle"
+version = "2.12.0"
+
+[[packages.wheels]]
+name = "pycodestyle-2.12.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/55/c4/bf8ede2d1641e0a2e027c6d0c7060e00332851ea772cc5cee42a4a207707/pycodestyle-2.12.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"
+
+[[packages]]
+name = "pycparser"
+version = "2.22"
+
+[[packages.wheels]]
+name = "pycparser-2.22-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"
+
+[[packages]]
+name = "pydantic"
+version = "2.11.7"
+
+[[packages.wheels]]
+name = "pydantic-2.11.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"
+
+[[packages]]
+name = "pydantic-ai-slim"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "pydantic_ai_slim-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d8/23/b4d52d83c302859e1e251a8c8a360b993cf8b4818c8b633adaa98b043556/pydantic_ai_slim-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d954ff84cb250d7150a7ed694e4f1f92f820205d036ee006d02fce3e62a3bc4e"
+
+[[packages]]
+name = "pydantic-core"
+version = "2.33.2"
+
+[[packages.wheels]]
+name = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"
+
+[[packages]]
+name = "pydantic-evals"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "pydantic_evals-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b6/6e/8d88e00f624a8348b286b219a292fe3e077ee973660dcff6b4ddd5a04e85/pydantic_evals-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "62035ae3a5321e4d892c7372ef91af0f46b675863e827f011d5cb8550dede400"
+
+[[packages]]
+name = "pydantic-graph"
+version = "0.2.9"
+
+[[packages.wheels]]
+name = "pydantic_graph-0.2.9-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a4/cc/e609261763a76f4d23a545afb462847592bc6b4d8eb412990b9b913c073e/pydantic_graph-0.2.9-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "38ad929a0ec205bd7d5875b0b408d4f13448276aa89b6ce2a1143a7552b070ce"
+
+[[packages]]
+name = "pydantic-settings"
+version = "2.8.1"
+
+[[packages.wheels]]
+name = "pydantic_settings-2.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c"
+
+[[packages]]
+name = "pydeck"
+version = "0.9.1"
+
+[[packages.wheels]]
+name = "pydeck-0.9.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038"
+
+[[packages]]
+name = "pydocstyle"
+version = "6.3.0"
+
+[[packages.wheels]]
+name = "pydocstyle-6.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/36/ea/99ddefac41971acad68f14114f38261c1f27dac0b3ec529824ebc739bdaa/pydocstyle-6.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"
+
+[[packages]]
+name = "pydot"
+version = "4.0.1"
+
+[[packages.wheels]]
+name = "pydot-4.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/32/a7125fb28c4261a627f999d5fb4afff25b523800faed2c30979949d6facd/pydot-4.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "869c0efadd2708c0be1f916eb669f3d664ca684bc57ffb7ecc08e70d5e93fee6"
+
+[[packages]]
+name = "pydub"
+version = "0.25.1"
+
+[[packages.wheels]]
+name = "pydub-0.25.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6"
+
+[[packages]]
+name = "pyerfa"
+version = "2.0.1.5"
+
+[[packages.wheels]]
+name = "pyerfa-2.0.1.5-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/b4/11/97233cf23ad5411ac6f13b1d6ee3888f90ace4f974d9bf9db887aa428912/pyerfa-2.0.1.5-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "66292d437dcf75925b694977aa06eb697126e7b86553e620371ed3e48b5e0ad0"
+
+[[packages]]
+name = "pyflakes"
+version = "3.2.0"
+
+[[packages.wheels]]
+name = "pyflakes-3.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"
+
+[[packages]]
+name = "pygithub"
+version = "2.6.1"
+
+[[packages.wheels]]
+name = "PyGithub-2.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ac/fc/a444cd19ccc8c4946a512f3827ed0b3565c88488719d800d54a75d541c0b/PyGithub-2.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6f2fa6d076ccae475f9fc392cc6cdbd54db985d4f69b8833a28397de75ed6ca3"
+
+[[packages]]
+name = "pygments"
+version = "2.19.1"
+
+[[packages.wheels]]
+name = "pygments-2.19.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"
+
+[[packages]]
+name = "pyjwt"
+version = "2.10.1"
+
+[[packages.wheels]]
+name = "PyJWT-2.10.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"
+
+[[packages]]
+name = "pylint"
+version = "3.3.6"
+
+[[packages.wheels]]
+name = "pylint-3.3.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/21/9537fc94aee9ec7316a230a49895266cf02d78aa29b0a2efbc39566e0935/pylint-3.3.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8b7c2d3e86ae3f94fb27703d521dd0b9b6b378775991f504d7c3a6275aa0a6a6"
+
+[[packages]]
+name = "pylint-venv"
+version = "3.0.4"
+
+[[packages.wheels]]
+name = "pylint_venv-3.0.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a6/10/040e1928236e3d34b26639e3427df88c7249a85aadc621cea2158589b4f8/pylint_venv-3.0.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "31006a3df398f58f962c9e5620e756b284e8b2bc490594ce5ee5da41920cb32c"
+
+[[packages]]
+name = "pyls-spyder"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "pyls_spyder-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d0/26/d0975972af1f18c3bb02ec5889191cc09ebb982bcbe45438d90ca763f4ec/pyls_spyder-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1505d975f866a343d0554b6dab41b53717f4b4bc6df450dfd7d48f889fe450b9"
+
+[[packages]]
+name = "pymongo"
+version = "4.10.1"
+
+[[packages.wheels]]
+name = "pymongo-4.10.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/0d/2a/7c24a6144eaa06d18ed52822ea2b0f119fd9267cd1abbb75dae4d89a3803/pymongo-4.10.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "45ee87a4e12337353242bc758accc7fb47a2f2d9ecc0382a61e64c8f01e86708"
+
+[[packages]]
+name = "pympler"
+version = "1.1"
+
+[[packages.wheels]]
+name = "Pympler-1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506"
+
+[[packages]]
+name = "pynacl"
+version = "1.5.0"
+
+[[packages.wheels]]
+name = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/5e/22/d3db169895faaf3e2eda892f005f433a62db2decbcfbc2f61e6517adfa87/PyNaCl-1.5.0-cp36-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"
+
+[[packages]]
+name = "pynndescent"
+version = "0.5.13"
+
+[[packages.wheels]]
+name = "pynndescent-0.5.13-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d2/53/d23a97e0a2c690d40b165d1062e2c4ccc796be458a1ce59f6ba030434663/pynndescent-0.5.13-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "69aabb8f394bc631b6ac475a1c7f3994c54adf3f51cd63b2730fefba5771b949"
+
+[[packages]]
+name = "pyodbc"
+version = "5.2.0"
+
+[[packages.wheels]]
+name = "pyodbc-5.2.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/73/2a/3219c8b7fa3788fc9f27b5fc2244017223cf070e5ab370f71c519adf9120/pyodbc-5.2.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "96d3127f28c0dacf18da7ae009cd48eac532d3dcc718a334b86a3c65f6a5ef5c"
+
+[[packages]]
+name = "pyogrio"
+version = "0.10.0"
+
+[[packages.wheels]]
+name = "pyogrio-0.10.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/27/5d/0deb16d228362a097ee3258d0a887c9c0add4b9678bb4847b08a241e124d/pyogrio-0.10.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "02e54bcfb305af75f829044b0045f74de31b77c2d6546f7aaf96822066147848"
+
+[[packages]]
+name = "pyomo"
+version = "6.9.2"
+
+[[packages.wheels]]
+name = "pyomo-6.9.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/88/0a07233e39357d3d620186485b927074d6d0ae0f64ad72cc5222ae05844e/pyomo-6.9.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "13ebb2f974f97afa626c2712d4f27e09a1c3d18ca11755676b743504a76e5161"
+
+[[packages]]
+name = "pypandoc"
+version = "1.15"
+
+[[packages.wheels]]
+name = "pypandoc-1.15-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/61/06/0763e0ccc81754d3eadb21b2cb86cf21bdedc9b52698c2ad6785db7f0a4e/pypandoc-1.15-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16"
+
+[[packages]]
+name = "pyparsing"
+version = "3.2.3"
+
+[[packages.wheels]]
+name = "pyparsing-3.2.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"
+
+[[packages]]
+name = "pypdf"
+version = "5.6.0"
+
+[[packages.wheels]]
+name = "pypdf-5.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/71/8b/dc3a72d98c22be7a4cbd664ad14c5a3e6295c2dbdf572865ed61e24b5e38/pypdf-5.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ca6bf446bfb0a2d8d71d6d6bb860798d864c36a29b3d9ae8d7fc7958c59f88e7"
+
+[[packages]]
+name = "pyproj"
+version = "3.7.0"
+
+[[packages.wheels]]
+name = "pyproj-3.7.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f8/33/3c8c6302717096b54aa14ccbb271045ba04629e21cbf348f2f2dc94f69b4/pyproj-3.7.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "10a8dc6ec61af97c89ff032647d743f8dc023645773da42ef43f7ae1125b3509"
+
+[[packages]]
+name = "pyproject-hooks"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "pyproject_hooks-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"
+
+[[packages]]
+name = "pyqt5"
+version = "5.15.11"
+
+[[packages.wheels]]
+name = "PyQt5-5.15.11-cp38-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/56/d5/68eb9f3d19ce65df01b6c7b7a577ad3bbc9ab3a5dd3491a4756e71838ec9/PyQt5-5.15.11-cp38-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517"
+
+[[packages]]
+name = "pyqt5-qt5"
+version = "5.15.2"
+
+[[packages.wheels]]
+name = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/37/97/5d3b222b924fa2ed4c2488925155cd0b03fd5d09ee1cfcf7c553c11c9f66/PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"
+
+[[packages]]
+name = "pyqt5-sip"
+version = "12.17.0"
+
+[[packages.wheels]]
+name = "PyQt5_sip-12.17.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/15/ed/ff94d6b2910e7627380cb1fc9a518ff966e6d78285c8e54c9422b68305db/PyQt5_sip-12.17.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "672c209d05661fab8e17607c193bf43991d268a1eefbc2c4551fbf30fd8bb2ca"
+
+[[packages]]
+name = "pyqtgraph"
+version = "0.13.7"
+
+[[packages.wheels]]
+name = "pyqtgraph-0.13.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/34/5702b3b7cafe99be1d94b42f100e8cc5e6957b761fcb1cf5f72d492851da/pyqtgraph-0.13.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7754edbefb6c367fa0dfb176e2d0610da3ada20aa7a5318516c74af5fb72bf7a"
+
+[[packages]]
+name = "pyqtwebengine"
+version = "5.15.7"
+
+[[packages.wheels]]
+name = "PyQtWebEngine-5.15.7-cp38-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/39/67/0dead50889d905fc99f40e61e5ab7f73746605ce8f74c4fa7fb3fc1d6c5e/PyQtWebEngine-5.15.7-cp38-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bd5e8c426d6f6b352cd15800d64a89b2a4a11e098460b818c7bdcf5e5612e44f"
+
+[[packages]]
+name = "pyqtwebengine-qt5"
+version = "5.15.2"
+
+[[packages.wheels]]
+name = "PyQtWebEngine_Qt5-5.15.2-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e0/db/0f29bd882aee8b5754f3e1ab104d2d09cdd9138a889558b43badcd81ce11/PyQtWebEngine_Qt5-5.15.2-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "24231f19e1595018779977de6722b5c69f3d03f34a5f7574ff21cd1e764ef76d"
+
+[[packages]]
+name = "pyreadline3"
+version = "3.5.4"
+
+[[packages.wheels]]
+name = "pyreadline3-3.5.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"
+
+[[packages]]
+name = "pyserial"
+version = "3.5"
+
+[[packages.wheels]]
+name = "pyserial-3.5-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/07/bc/587a445451b253b285629263eb51c2d8e9bcea4fc97826266d186f96f558/pyserial-3.5-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"
+
+[[packages]]
+name = "pysocks"
+version = "1.7.1"
+
+[[packages.wheels]]
+name = "PySocks-1.7.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"
+
+[[packages]]
+name = "pyspnego"
+version = "0.11.2"
+
+[[packages.wheels]]
+name = "pyspnego-0.11.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/57/ea/b3c1438839d8724beff7b31ec42b9d041265dc9ca27ccb54477d442bfbcf/pyspnego-0.11.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "74abc1fb51e59360eb5c5c9086e5962174f1072c7a50cf6da0bda9a4bcfdfbd4"
+
+[[packages]]
+name = "pytest"
+version = "8.3.5"
+
+[[packages.wheels]]
+name = "pytest-8.3.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"
+
+[[packages]]
+name = "python-barcode"
+version = "0.15.1"
+
+[[packages.wheels]]
+name = "python_barcode-0.15.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/10/27/9b5c5bb1938d4e6b12f4c95f40ea905c11df3cd58e128e9305397b9a2697/python_barcode-0.15.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "057636fba37369c22852410c8535b36adfbeb965ddfd4e5b6924455d692e0886"
+
+[[packages]]
+name = "python-dateutil"
+version = "2.8.2"
+
+[[packages.wheels]]
+name = "python_dateutil-2.8.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
+
+[[packages]]
+name = "python-dotenv"
+version = "1.1.0"
+
+[[packages.wheels]]
+name = "python_dotenv-1.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d"
+
+[[packages]]
+name = "python-json-logger"
+version = "3.3.0"
+
+[[packages.wheels]]
+name = "python_json_logger-3.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7"
+
+[[packages]]
+name = "python-lsp-black"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "python_lsp_black-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/78/44/fef9b4d027b3d6321e6f30b6b5946bef18cd84a96e1d81012ac0f69ea53c/python_lsp_black-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d5efdee45f5fa9e5241f5d4d396cd46127f45c85817916b1fd92c2986652bf7e"
+
+[[packages]]
+name = "python-lsp-jsonrpc"
+version = "1.1.2"
+
+[[packages.wheels]]
+name = "python_lsp_jsonrpc-1.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cb/d9/656659d5b5d5f402b2b174cd0ba9bc827e07ce3c0bf88da65424baf64af8/python_lsp_jsonrpc-1.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c"
+
+[[packages]]
+name = "python-lsp-server"
+version = "1.12.2"
+
+[[packages.wheels]]
+name = "python_lsp_server-1.12.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cb/e7/28010a326ef591e1409daf9d57a47de94156c147ad1befe74d8196d82729/python_lsp_server-1.12.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "750116459449184ba20811167cdf96f91296ae12f1f65ebd975c5c159388111b"
+
+[[packages]]
+name = "python-multipart"
+version = "0.0.20"
+
+[[packages.wheels]]
+name = "python_multipart-0.0.20-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"
+
+[[packages]]
+name = "python-slugify"
+version = "8.0.4"
+
+[[packages.wheels]]
+name = "python_slugify-8.0.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"
+
+[[packages]]
+name = "pythonqwt"
+version = "0.14.5"
+
+[[packages.wheels]]
+name = "pythonqwt-0.14.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/28/e9/1e6e93e1aaaec57d6ef427291e8fb3d9f18ebd91147c24f2b241b01e2def/pythonqwt-0.14.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "be5a9d2e1ba22aaa02eb397c5b3b5e4e1d9ed2c08f45554d8b920d8fc3be6dc7"
+
+[[packages]]
+name = "pytoolconfig"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "pytoolconfig-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/92/44/da239917f5711ca7105f7d7f9e2765716dd883b241529beafc0f28504725/pytoolconfig-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5d8cea8ae1996938ec3eaf44567bbc5ef1bc900742190c439a44a704d6e1b62b"
+
+[[packages]]
+name = "pytz"
+version = "2025.2"
+
+[[packages.wheels]]
+name = "pytz-2025.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"
+
+[[packages]]
+name = "pyuca"
+version = "1.2"
+
+[[packages.wheels]]
+name = "pyuca-1.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/98/88/aeeee34d88f841aca712a8c18fbd62a33eaad8f2dbe535e87f3c829b02f9/pyuca-1.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "abaa12e1bd2c7c68ca8396ff8383bc0654a739cef3ae68fd7af58bf29af0a91e"
+
+[[packages]]
+name = "pyusb"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "pyusb-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430"
+
+[[packages]]
+name = "pywavelets"
+version = "1.8.0"
+
+[[packages.wheels]]
+name = "pywavelets-1.8.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c9/4f/0a709a5732e6cf9297fc87bf545cb879997cde204115f8c0cbc296c5bdd3/pywavelets-1.8.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4dbebcfd55ea8a85b7fc8802d411e75337170422abf6e96019d7e46c394e80e5"
+
+[[packages]]
+name = "pywin32"
+version = "310"
+
+[[packages.wheels]]
+name = "pywin32-310-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"
+
+[[packages]]
+name = "pywin32-ctypes"
+version = "0.2.3"
+
+[[packages.wheels]]
+name = "pywin32_ctypes-0.2.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"
+
+[[packages]]
+name = "pywinpty"
+version = "2.0.15"
+
+[[packages.wheels]]
+name = "pywinpty-2.0.15-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/fb/16/2ab7b3b7f55f3c6929e5f629e1a68362981e4e5fed592a2ed1cb4b4914a5/pywinpty-2.0.15-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408"
+
+[[packages]]
+name = "pyyaml"
+version = "6.0.2"
+
+[[packages.wheels]]
+name = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"
+
+[[packages]]
+name = "pyzmq"
+version = "26.4.0"
+
+[[packages.wheels]]
+name = "pyzmq-26.4.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c6/6c/f289c1789d7bb6e5a3b3bef7b2a55089b8561d17132be7d960d3ff33b14e/pyzmq-26.4.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b"
+
+[[packages]]
+name = "qdarkstyle"
+version = "3.2.3"
+
+[[packages.wheels]]
+name = "QDarkStyle-3.2.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/93/7d/c3c10498430dadcea4def5faddf71cd199e577d20a125e7ef1e9d7bdbbfa/QDarkStyle-3.2.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ea980ee426d594909cf1058306832af71ff6cbad6f69237b036d1550635aefbc"
+
+[[packages]]
+name = "qdldl"
+version = "0.1.7.post5"
+
+[[packages.wheels]]
+name = "qdldl-0.1.7.post5-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/08/f7/abac03a09f6848cee6d5dd7a7a8bd1dfed68766ee77f9cbf3e9de596ad68/qdldl-0.1.7.post5-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "cc9be378e7bec67d4c62b7fa27cafb4f77d3e5e059d753c3dce0a5ae1ef5fea0"
+
+[[packages]]
+name = "qrcode"
+version = "8.2"
+
+[[packages.wheels]]
+name = "qrcode-8.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/dd/b8/d2d6d731733f51684bbf76bf34dab3b70a9148e8f2cef2bb544fccec681a/qrcode-8.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f"
+
+[[packages]]
+name = "qstylizer"
+version = "0.2.4"
+
+[[packages.wheels]]
+name = "qstylizer-0.2.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2d/ba/2a4e51861942c2bc3be60400c69f6713359c3e307aee4696f2ea47f35811/qstylizer-0.2.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8f384dfe86f9edb0bb596b93663a51f124f0794b94fd54057cc7cf9cea59fb6f"
+
+[[packages]]
+name = "qtawesome"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "qtawesome-1.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a5/ee/6e6c6715129c929af2d95ddb2e9decf54c1beffe58f336911197aacc0448/qtawesome-1.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a4d689fa071c595aa6184171ce1f0f847677cb8d2db45382c43129f1d72a3d93"
+
+[[packages]]
+name = "qtconsole"
+version = "5.6.1"
+
+[[packages.wheels]]
+name = "qtconsole-5.6.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c6/8a/635610fb6131bc702229e2780d7b042416866ab78f8ed1ff24c4b23a2f4c/qtconsole-5.6.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3d22490d9589bace566ad4f3455b61fa2209156f40e87e19e2c3cb64e9264950"
+
+[[packages]]
+name = "qtpy"
+version = "2.4.3"
+
+[[packages.wheels]]
+name = "QtPy-2.4.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/69/76/37c0ccd5ab968a6a438f9c623aeecc84c202ab2fabc6a8fd927580c15b5a/QtPy-2.4.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72095afe13673e017946cc258b8d5da43314197b741ed2890e563cf384b51aa1"
+
+[[packages]]
+name = "quantecon"
+version = "0.8.1"
+
+[[packages.wheels]]
+name = "quantecon-0.8.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/53/d6/3dd2bea4395988a2a614eebaafd2b478ffd36243e0dbc2bad4aaaf4c1bf7/quantecon-0.8.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a1f041ed2ed6a9a88e2206998eed85217d3ca903937017cabadfd5a35cbe632e"
+
+[[packages]]
+name = "quart"
+version = "0.20.0"
+
+[[packages.wheels]]
+name = "quart-0.20.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7e/e9/cc28f21f52913adf333f653b9e0a3bf9cb223f5083a26422968ba73edd8d/quart-0.20.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "003c08f551746710acb757de49d9b768986fd431517d0eb127380b656b98b8f1"
+
+[[packages]]
+name = "rapidfuzz"
+version = "3.13.0"
+
+[[packages.wheels]]
+name = "rapidfuzz-3.13.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/96/e3/a98c25c4f74051df4dcf2f393176b8663bfd93c7afc6692c84e96de147a2/rapidfuzz-3.13.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "9a7c6232be5f809cd39da30ee5d24e6cadd919831e6020ec6c2391f4c3bc9264"
+
+[[packages]]
+name = "readme-renderer"
+version = "44.0"
+
+[[packages.wheels]]
+name = "readme_renderer-44.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"
+
+[[packages]]
+name = "redis"
+version = "5.2.1"
+
+[[packages.wheels]]
+name = "redis-5.2.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3c/5f/fa26b9b2672cbe30e07d9a5bdf39cf16e3b80b42916757c5f92bca88e4ba/redis-5.2.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"
+
+[[packages]]
+name = "referencing"
+version = "0.36.2"
+
+[[packages.wheels]]
+name = "referencing-0.36.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"
+
+[[packages]]
+name = "regex"
+version = "2024.11.6"
+
+[[packages.wheels]]
+name = "regex-2024.11.6-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"
+
+[[packages]]
+name = "reportlab"
+version = "4.4.2"
+
+[[packages.wheels]]
+name = "reportlab-4.4.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/74/ed990bc9586605d4e46f6b0e0b978a5b8e757aa599e39664bee26d6dc666/reportlab-4.4.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "58e11be387457928707c12153b7e41e52533a5da3f587b15ba8f8fd0805c6ee2"
+
+[[packages]]
+name = "requests"
+version = "2.32.4"
+
+[[packages.wheels]]
+name = "requests-2.32.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"
+
+[[packages]]
+name = "requests-ntlm"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "requests_ntlm-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/5d/836b97537a390cf811b0488490c389c5a614f0a93acb23f347bd37a2d914/requests_ntlm-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4c7534a7d0e482bb0928531d621be4b2c74ace437e88c5a357ceb7452d25a510"
+
+[[packages]]
+name = "requests-toolbelt"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "requests_toolbelt-1.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"
+
+[[packages]]
+name = "rfc3339-validator"
+version = "0.1.4"
+
+[[packages.wheels]]
+name = "rfc3339_validator-0.1.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"
+
+[[packages]]
+name = "rfc3986"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "rfc3986-2.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"
+
+[[packages]]
+name = "rfc3986-validator"
+version = "0.1.1"
+
+[[packages.wheels]]
+name = "rfc3986_validator-0.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"
+
+[[packages]]
+name = "rich"
+version = "14.0.0"
+
+[[packages.wheels]]
+name = "rich-14.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"
+
+[[packages]]
+name = "rope"
+version = "1.13.0"
+
+[[packages.wheels]]
+name = "rope-1.13.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a0/d0/e213e5adfa162e437dff3669131dc476043fc3a22fe99ef891516100610d/rope-1.13.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b435a0c0971244fdcd8741676a9fae697ae614c20cc36003678a7782f25c0d6c"
+
+[[packages]]
+name = "rpds-py"
+version = "0.24.0"
+
+[[packages.wheels]]
+name = "rpds_py-0.24.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f9/12/09e048d1814195e01f354155fb772fb0854bd3450b5f5a82224b3a319f0e/rpds_py-0.24.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a"
+
+[[packages]]
+name = "rsa"
+version = "4.7.2"
+
+[[packages.wheels]]
+name = "rsa-4.7.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e9/93/0c0f002031f18b53af7a6166103c02b9c0667be528944137cc954ec921b3/rsa-4.7.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"
+
+[[packages]]
+name = "rtree"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "rtree-1.4.0-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/ce/c2/362f2cc36a7a57b47380061c23fc109c7222c1a544ffd24cda289ba19673/rtree-1.4.0-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ba83efc7b7563905b1bfdfc14490c4bfb59e92e5e6156bdeb6ec5df5117252f4"
+
+[[packages]]
+name = "rx"
+version = "3.2.0"
+
+[[packages.wheels]]
+name = "Rx-3.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e2/a9/efeaeca4928a9a56d04d609b5730994d610c82cf4d9dd7aa173e6ef4233e/Rx-3.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "922c5f4edb3aa1beaa47bf61d65d5380011ff6adcd527f26377d05cb73ed8ec8"
+
+[[packages]]
+name = "scikit-image"
+version = "0.25.2"
+
+[[packages.wheels]]
+name = "scikit_image-0.25.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/8a/97/5fcf332e1753831abb99a2525180d3fb0d70918d461ebda9873f66dcc12f/scikit_image-0.25.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "64785a8acefee460ec49a354706db0b09d1f325674107d7fa3eadb663fb56d6f"
+
+[[packages]]
+name = "scikit-learn"
+version = "1.7.1"
+
+[[packages.wheels]]
+name = "scikit_learn-1.7.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e2/47/9291cfa1db1dae9880420d1e07dbc7e8dd4a7cdbc42eaba22512e6bde958/scikit_learn-1.7.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ca6d31fb10e04d50bfd2b50d66744729dbb512d4efd0223b864e2fdbfc4cee11"
+
+[[packages]]
+name = "scipy"
+version = "1.16.0"
+
+[[packages.wheels]]
+name = "scipy-1.16.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7c/a7/4c94bbe91f12126b8bf6709b2471900577b7373a4fd1f431f28ba6f81115/scipy-1.16.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe"
+
+[[packages]]
+name = "scramp"
+version = "1.4.5"
+
+[[packages.wheels]]
+name = "scramp-1.4.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d9/9f/8b2f2749ccfbe4fcef08650896ac47ed919ff25b7ac57b7a1ae7da16c8c3/scramp-1.4.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "50e37c464fc67f37994e35bee4151e3d8f9320e9c204fca83a5d313c121bbbe7"
+
+[[packages]]
+name = "scs"
+version = "3.2.7.post2"
+
+[[packages.wheels]]
+name = "scs-3.2.7.post2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/9d/f9/840ef19a298ef7099f4a692772001f2f552b0917a3fb230f872a1c40ba11/scs-3.2.7.post2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a2c48cd19e39bf87dae0b20a289fff44930458fc2ca2afa0f899058dc41e5545"
+
+[[packages]]
+name = "seaborn"
+version = "0.13.2"
+
+[[packages.wheels]]
+name = "seaborn-0.13.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987"
+
+[[packages]]
+name = "send2trash"
+version = "1.8.3"
+
+[[packages.wheels]]
+name = "Send2Trash-1.8.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9"
+
+[[packages]]
+name = "setuptools"
+version = "80.9.0"
+
+[[packages.wheels]]
+name = "setuptools-80.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"
+
+[[packages]]
+name = "shapely"
+version = "2.1.1"
+
+[[packages.wheels]]
+name = "shapely-2.1.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/12/d9/6d13b8957a17c95794f0c4dfb65ecd0957e6c7131a56ce18d135c1107a52/shapely-2.1.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "ab8d878687b438a2f4c138ed1a80941c6ab0029e0f4c785ecfe114413b498a97"
+
+[[packages]]
+name = "shellingham"
+version = "1.5.4"
+
+[[packages.wheels]]
+name = "shellingham-1.5.4-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"
+
+[[packages]]
+name = "simplejson"
+version = "3.19.3"
+
+[[packages.wheels]]
+name = "simplejson-3.19.3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e2/58/b06226e6b0612f2b1fa13d5273551da259f894566b1eef32249ddfdcce44/simplejson-3.19.3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "3bbcdc438dc1683b35f7a8dc100960c721f922f9ede8127f63bed7dfded4c64c"
+
+[[packages]]
+name = "simpy"
+version = "4.1.1"
+
+[[packages.wheels]]
+name = "simpy-4.1.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/48/72/920ed1224c94a8a5a69e6c1275ac7fe4eb911ba8feffddf469f1629d47f3/simpy-4.1.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7c5ae380240fd2238671160e4830956f8055830a8317edf5c05e495b3823cd88"
+
+[[packages]]
+name = "six"
+version = "1.17.0"
+
+[[packages.wheels]]
+name = "six-1.17.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"
+
+[[packages]]
+name = "skrub"
+version = "0.6.0"
+
+[[packages.wheels]]
+name = "skrub-0.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/c3/33087009e113b247a2ee58ff3a2a93c51d43cc4f0a3400f6fdb11deea6dc/skrub-0.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "bc7155ca02fb4233abce843716b175619d95b94fb7b9ead4b15fc26453d8f646"
+
+[[packages]]
+name = "smmap"
+version = "5.0.2"
+
+[[packages.wheels]]
+name = "smmap-5.0.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"
+
+[[packages]]
+name = "sniffio"
+version = "1.3.1"
+
+[[packages.wheels]]
+name = "sniffio-1.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"
+
+[[packages]]
+name = "snowballstemmer"
+version = "2.2.0"
+
+[[packages.wheels]]
+name = "snowballstemmer-2.2.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"
+
+[[packages]]
+name = "sortedcontainers"
+version = "2.4.0"
+
+[[packages.wheels]]
+name = "sortedcontainers-2.4.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"
+
+[[packages]]
+name = "sounddevice"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "sounddevice-0.5.1-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/af/9b/15217b04f3b36d30de55fef542389d722de63f1ad81f9c72d8afc98cb6ab/sounddevice-0.5.1-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1"
+
+[[packages]]
+name = "soupsieve"
+version = "2.6"
+
+[[packages.wheels]]
+name = "soupsieve-2.6-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"
+
+[[packages]]
+name = "sphinx"
+version = "8.1.3"
+
+[[packages.wheels]]
+name = "sphinx-8.1.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"
+
+[[packages]]
+name = "sphinx-rtd-theme"
+version = "3.0.2"
+
+[[packages.wheels]]
+name = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"
+
+[[packages]]
+name = "sphinxcontrib-applehelp"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"
+
+[[packages]]
+name = "sphinxcontrib-devhelp"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"
+
+[[packages]]
+name = "sphinxcontrib-htmlhelp"
+version = "2.1.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"
+
+[[packages]]
+name = "sphinxcontrib-jquery"
+version = "4.1"
+
+[[packages.wheels]]
+name = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"
+
+[[packages]]
+name = "sphinxcontrib-jsmath"
+version = "1.0.1"
+
+[[packages.wheels]]
+name = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"
+
+[[packages]]
+name = "sphinxcontrib-qthelp"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"
+
+[[packages]]
+name = "sphinxcontrib-serializinghtml"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"
+
+[[packages]]
+name = "spyder"
+version = "6.0.7"
+
+[[packages.wheels]]
+name = "spyder-6.0.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ee/c8/1568fa96351ddad878d42e7487d9637604c7f34030171acf810f47914d9d/spyder-6.0.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b725569bb8ddc7b0aab73d747d85312dc0456978370cc0f9b1a101c0fe4f076b"
+
+[[packages]]
+name = "spyder-kernels"
+version = "3.0.5"
+
+[[packages.wheels]]
+name = "spyder_kernels-3.0.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/10/2d/b1c88e914ebdec2a9cf066b2c283ee234f4052c31922017407fa8adb89f3/spyder_kernels-3.0.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9cc808e0ec4426b9ba911128e221fa2234e6c8d6e08526132e90112ff9c2bb7c"
+
+[[packages]]
+name = "sqlalchemy"
+version = "2.0.41"
+
+[[packages.wheels]]
+name = "sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df"
+
+[[packages]]
+name = "sqlite-bro"
+version = "0.13.1"
+
+[[packages.wheels]]
+name = "sqlite_bro-0.13.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/b3/81b91f5b26fff329c59dbf826a87637bd51d1903120427912322f86e7d33/sqlite_bro-0.13.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d"
+
+[[packages]]
+name = "sqlite-fts4"
+version = "1.0.3"
+
+[[packages.wheels]]
+name = "sqlite_fts4-1.0.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/51/29/0096e8b1811aaa78cfb296996f621f41120c21c2f5cd448ae1d54979d9fc/sqlite_fts4-1.0.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0359edd8dea6fd73c848989e1e2b1f31a50fe5f9d7272299ff0e8dbaa62d035f"
+
+[[packages]]
+name = "sqlite-utils"
+version = "3.38"
+
+[[packages.wheels]]
+name = "sqlite_utils-3.38-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4d/eb/f8e8e827805f810838efff3311cccd2601238c5fa3fc35c1f878709e161b/sqlite_utils-3.38-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8a27441015c3b2ef475f555861f7a2592f73bc60d247af9803a11b65fc605bf9"
+
+[[packages]]
+name = "sqlparse"
+version = "0.5.3"
+
+[[packages.wheels]]
+name = "sqlparse-0.5.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"
+
+[[packages]]
+name = "squarify"
+version = "0.4.4"
+
+[[packages.wheels]]
+name = "squarify-0.4.4-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/3c/eedbe9fb07cc20fd9a8423da14b03bc270d0570b3ba9174a4497156a2152/squarify-0.4.4-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d7597724e29d48aa14fd2f551060d6b09e1f0a67e4cd3ea329fe03b4c9a56f11"
+
+[[packages]]
+name = "sse-starlette"
+version = "2.4.1"
+
+[[packages.wheels]]
+name = "sse_starlette-2.4.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e4/f1/6c7eaa8187ba789a6dd6d74430307478d2a91c23a5452ab339b6fbe15a08/sse_starlette-2.4.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "08b77ea898ab1a13a428b2b6f73cfe6d0e607a7b4e15b9bb23e4a37b087fd39a"
+
+[[packages]]
+name = "sspilib"
+version = "0.2.0"
+
+[[packages.wheels]]
+name = "sspilib-0.2.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/49/ad/40f898075c913c75060c17c9cc6d6b86e8f83b6f5e1e017627b07ff53fcd/sspilib-0.2.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "c39a698491f43618efca8776a40fb7201d08c415c507f899f0df5ada15abefaa"
+
+[[packages]]
+name = "stack-data"
+version = "0.6.3"
+
+[[packages.wheels]]
+name = "stack_data-0.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"
+
+[[packages]]
+name = "starlette"
+version = "0.46.2"
+
+[[packages.wheels]]
+name = "starlette-0.46.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35"
+
+[[packages]]
+name = "statsmodels"
+version = "0.14.4"
+
+[[packages.wheels]]
+name = "statsmodels-0.14.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/1d/eb/cb8b01f5edf8f135eb3d0553d159db113a35b2948d0e51eeb735e7ae09ea/statsmodels-0.14.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "81030108d27aecc7995cac05aa280cf8c6025f6a6119894eef648997936c2dd0"
+
+[[packages]]
+name = "streamlit"
+version = "1.46.1"
+
+[[packages.wheels]]
+name = "streamlit-1.46.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/3b/35400175788cdd6a43c90dce1e7f567eb6843a3ba0612508c0f19ee31f5f/streamlit-1.46.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dffa373230965f87ccc156abaff848d7d731920cf14106f3b99b1ea18076f728"
+
+[[packages]]
+name = "superqt"
+version = "0.7.3"
+
+[[packages.wheels]]
+name = "superqt-0.7.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4f/53/ce8e705a0fca9ff08406d0232409c6dacd09a04cdc5124e33aa3ad97c117/superqt-0.7.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8f7d141665b31baa484747f324fc9fc2d14223f2fefc92ffed6ea35c92221304"
+
+[[packages]]
+name = "sv-ttk"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "sv_ttk-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/3d/be0abc3202e90f282ad465f4e7c6e41bc8dce810ce5d1611566a1e7dfba8/sv_ttk-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"
+
+[[packages]]
+name = "sympy"
+version = "1.14.0"
+
+[[packages.wheels]]
+name = "sympy-1.14.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"
+
+[[packages]]
+name = "tabulate"
+version = "0.9.0"
+
+[[packages.wheels]]
+name = "tabulate-0.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"
+
+[[packages]]
+name = "tblib"
+version = "3.1.0"
+
+[[packages.wheels]]
+name = "tblib-3.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/27/44/aa5c8b10b2cce7a053018e0d132bd58e27527a0243c4985383d5b6fd93e9/tblib-3.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "670bb4582578134b3d81a84afa1b016128b429f3d48e6cbbaecc9d15675e984e"
+
+[[packages]]
+name = "tenacity"
+version = "9.1.2"
+
+[[packages.wheels]]
+name = "tenacity-9.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"
+
+[[packages]]
+name = "termcolor"
+version = "3.1.0"
+
+[[packages.wheels]]
+name = "termcolor-3.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4f/bd/de8d508070629b6d84a30d01d57e4a65c69aa7f5abe7560b8fad3b50ea59/termcolor-3.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa"
+
+[[packages]]
+name = "terminado"
+version = "0.18.1"
+
+[[packages.wheels]]
+name = "terminado-0.18.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"
+
+[[packages]]
+name = "text-unidecode"
+version = "1.3"
+
+[[packages.wheels]]
+name = "text_unidecode-1.3-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"
+
+[[packages]]
+name = "textdistance"
+version = "4.6.3"
+
+[[packages.wheels]]
+name = "textdistance-4.6.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c6/c2/c62601c858010b0513a6434b9be19bd740533a6e861eddfd30b7258d92a0/textdistance-4.6.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0cb1b2cc8e3339ddc3e0f8c870e49fb49de6ecc42a718917308b3c971f34aa56"
+
+[[packages]]
+name = "thefuzz"
+version = "0.22.1"
+
+[[packages.wheels]]
+name = "thefuzz-0.22.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/4f/1695e70ceb3604f19eda9908e289c687ea81c4fecef4d90a9d1d0f2f7ae9/thefuzz-0.22.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "59729b33556850b90e1093c4cf9e618af6f2e4c985df193fdf3c5b5cf02ca481"
+
+[[packages]]
+name = "threadpoolctl"
+version = "3.6.0"
+
+[[packages.wheels]]
+name = "threadpoolctl-3.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"
+
+[[packages]]
+name = "three-merge"
+version = "0.1.1"
+
+[[packages.wheels]]
+name = "three_merge-0.1.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/23/be/a52588102605ec52b4e88340d65a290b6465c1dbcd2d943ab149b012908b/three_merge-0.1.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dd219f4696aa0bbec6099ac3528b4de0450ff9bde862dd8f6d6f52e745f83464"
+
+[[packages]]
+name = "tifffile"
+version = "2025.3.30"
+
+[[packages.wheels]]
+name = "tifffile-2025.3.30-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6e/be/10d23cfd4078fbec6aba768a357eff9e70c0b6d2a07398425985c524ad2a/tifffile-2025.3.30-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0ed6eee7b66771db2d1bfc42262a51b01887505d35539daef118f4ff8c0f629c"
+
+[[packages]]
+name = "tiktoken"
+version = "0.9.0"
+
+[[packages.wheels]]
+name = "tiktoken-0.9.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/de/a8/8f499c179ec900783ffe133e9aab10044481679bb9aad78436d239eee716/tiktoken-0.9.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95"
+
+[[packages]]
+name = "tinycss2"
+version = "1.4.0"
+
+[[packages.wheels]]
+name = "tinycss2-1.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"
+
+[[packages]]
+name = "tokenizers"
+version = "0.21.1"
+
+[[packages.wheels]]
+name = "tokenizers-0.21.1-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e6/b6/072a8e053ae600dcc2ac0da81a23548e3b523301a442a6ca900e92ac35be/tokenizers-0.21.1-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "0f0dcbcc9f6e13e675a66d7a5f2f225a736745ce484c1a4e07476a89ccdad382"
+
+[[packages]]
+name = "toml"
+version = "0.10.2"
+
+[[packages.wheels]]
+name = "toml-0.10.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"
+
+[[packages]]
+name = "tomli"
+version = "2.2.1"
+
+[[packages.wheels]]
+name = "tomli-2.2.1-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"
+
+[[packages]]
+name = "tomli-w"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "tomli_w-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90"
+
+[[packages]]
+name = "tomlkit"
+version = "0.13.2"
+
+[[packages.wheels]]
+name = "tomlkit-0.13.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"
+
+[[packages]]
+name = "toolz"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "toolz-1.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236"
+
+[[packages]]
+name = "tornado"
+version = "6.5.1"
+
+[[packages.wheels]]
+name = "tornado-6.5.1-cp39-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/7b/09/6526e32bf1049ee7de3bebba81572673b19a2a8541f795d887e92af1a8bc/tornado-6.5.1-cp39-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b"
+
+[[packages]]
+name = "tqdm"
+version = "4.67.1"
+
+[[packages.wheels]]
+name = "tqdm-4.67.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"
+
+[[packages]]
+name = "traitlets"
+version = "5.14.3"
+
+[[packages.wheels]]
+name = "traitlets-5.14.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"
+
+[[packages]]
+name = "traittypes"
+version = "0.2.1"
+
+[[packages.wheels]]
+name = "traittypes-0.2.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9c/d1/8d5bd662703cc1764d986f6908a608777305946fa634d34c470cd4a1e729/traittypes-0.2.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1340af133810b6eee1a2eb2e988f862b0d12b6c2d16f282aaf3207b782134c2e"
+
+[[packages]]
+name = "trio"
+version = "0.30.0"
+
+[[packages.wheels]]
+name = "trio-0.30.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/69/8e/3f6dfda475ecd940e786defe6df6c500734e686c9cd0a0f8ef6821e9b2f2/trio-0.30.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3bf4f06b8decf8d3cf00af85f40a89824669e2d033bb32469d34840edcfc22a5"
+
+[[packages]]
+name = "trove-classifiers"
+version = "2025.5.9.12"
+
+[[packages.wheels]]
+name = "trove_classifiers-2025.5.9.12-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/92/ef/c6deb083748be3bcad6f471b6ae983950c161890bf5ae1b2af80cc56c530/trove_classifiers-2025.5.9.12-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e381c05537adac78881c8fa345fd0e9970159f4e4a04fcc42cfd3129cca640ce"
+
+[[packages]]
+name = "twine"
+version = "6.1.0"
+
+[[packages.wheels]]
+name = "twine-6.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7c/b6/74e927715a285743351233f33ea3c684528a0d374d2e43ff9ce9585b73fe/twine-6.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"
+
+[[packages]]
+name = "typer"
+version = "0.15.2"
+
+[[packages.wheels]]
+name = "typer-0.15.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc"
+
+[[packages]]
+name = "types-python-dateutil"
+version = "2.9.0.20240316"
+
+[[packages.wheels]]
+name = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c7/1b/af4f4c4f3f7339a4b7eb3c0ab13416db98f8ac09de3399129ee5fdfa282b/types_python_dateutil-2.9.0.20240316-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"
+
+[[packages]]
+name = "types-requests"
+version = "2.32.0.20250328"
+
+[[packages.wheels]]
+name = "types_requests-2.32.0.20250328-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/cc/15/3700282a9d4ea3b37044264d3e4d1b1f0095a4ebf860a99914fd544e3be3/types_requests-2.32.0.20250328-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "72ff80f84b15eb3aa7a8e2625fffb6a93f2ad5a0c20215fc1dcfa61117bcb2a2"
+
+[[packages]]
+name = "typing-extensions"
+version = "4.13.2"
+
+[[packages.wheels]]
+name = "typing_extensions-4.13.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"
+
+[[packages]]
+name = "typing-inspection"
+version = "0.4.0"
+
+[[packages.wheels]]
+name = "typing_inspection-0.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"
+
+[[packages]]
+name = "tzdata"
+version = "2025.2"
+
+[[packages.wheels]]
+name = "tzdata-2025.2-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"
+
+[[packages]]
+name = "tzlocal"
+version = "5.3.1"
+
+[[packages.wheels]]
+name = "tzlocal-5.3.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d"
+
+[[packages]]
+name = "ujson"
+version = "5.10.0"
+
+[[packages.wheels]]
+name = "ujson-5.10.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/d7/72/6cb6728e2738c05bbe9bd522d6fc79f86b9a28402f38663e85a28fddd4a0/ujson-5.10.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"
+
+[[packages]]
+name = "umap-learn"
+version = "0.5.7"
+
+[[packages.wheels]]
+name = "umap_learn-0.5.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3c/8f/671c0e1f2572ba625cbcc1faeba9435e00330c3d6962858711445cf1e817/umap_learn-0.5.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6a7e0be2facfa365a5ed6588447102bdbef32a0ef449535c25c97ea7e680073c"
+
+[[packages]]
+name = "uncertainties"
+version = "3.2.2"
+
+[[packages.wheels]]
+name = "uncertainties-3.2.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fa/fc/97711d2a502881d871e3cf2d2645e21e7f8e4d4fd9a56937557790cade6a/uncertainties-3.2.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "fd8543355952f4052786ed4150acaf12e23117bd0f5bd03ea07de466bce646e7"
+
+[[packages]]
+name = "uri-template"
+version = "1.3.0"
+
+[[packages.wheels]]
+name = "uri_template-1.3.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"
+
+[[packages]]
+name = "urllib3"
+version = "2.4.0"
+
+[[packages.wheels]]
+name = "urllib3-2.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
+
+[[packages]]
+name = "uvicorn"
+version = "0.34.2"
+
+[[packages.wheels]]
+name = "uvicorn-0.34.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403"
+
+[[packages]]
+name = "vega-datasets"
+version = "0.9.0"
+
+[[packages.wheels]]
+name = "vega_datasets-0.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e6/9f/ca52771fe972e0dcc5167fedb609940e01516066938ff2ee28b273ae4f29/vega_datasets-0.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3d7c63917be6ca9b154b565f4779a31fedce57b01b5b9d99d8a34a7608062a1d"
+
+[[packages]]
+name = "waitress"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "waitress-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5b/a9/485c953a1ac4cb98c28e41fd2c7184072df36bbf99734a51d44d04176878/waitress-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"
+
+[[packages]]
+name = "watchdog"
+version = "6.0.0"
+
+[[packages.wheels]]
+name = "watchdog-6.0.0-py3-none-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"
+
+[[packages]]
+name = "wcwidth"
+version = "0.2.13"
+
+[[packages.wheels]]
+name = "wcwidth-0.2.13-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"
+
+[[packages]]
+name = "webcolors"
+version = "24.11.1"
+
+[[packages.wheels]]
+name = "webcolors-24.11.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9"
+
+[[packages]]
+name = "webencodings"
+version = "0.5.1"
+
+[[packages.wheels]]
+name = "webencodings-0.5.1-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"
+
+[[packages]]
+name = "websocket-client"
+version = "1.8.0"
+
+[[packages.wheels]]
+name = "websocket_client-1.8.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"
+
+[[packages]]
+name = "websockets"
+version = "14.2"
+
+[[packages.wheels]]
+name = "websockets-14.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f"
+
+[[packages]]
+name = "werkzeug"
+version = "3.1.3"
+
+[[packages.wheels]]
+name = "werkzeug-3.1.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"
+
+[[packages]]
+name = "whatthepatch"
+version = "1.0.7"
+
+[[packages.wheels]]
+name = "whatthepatch-1.0.7-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8e/93/af1d6ccb69ab6b5a00e03fa0cefa563f9862412667776ea15dd4eece3a90/whatthepatch-1.0.7-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1b6f655fd31091c001c209529dfaabbabdbad438f5de14e3951266ea0fc6e7ed"
+
+[[packages]]
+name = "wheel"
+version = "0.45.1"
+
+[[packages.wheels]]
+name = "wheel-0.45.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"
+
+[[packages]]
+name = "widgetsnbextension"
+version = "4.0.14"
+
+[[packages.wheels]]
+name = "widgetsnbextension-4.0.14-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575"
+
+[[packages]]
+name = "wordcloud"
+version = "1.9.4"
+
+[[packages.wheels]]
+name = "wordcloud-1.9.4-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/84/47/d482f7d2decc6e59e69e105b12c53d6d2967f0d703e664484c5f2f87fca8/wordcloud-1.9.4-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "8c9a5af2fbcf029a19e827adbee58e86efe7536dca7a42380a8601113a86069b"
+
+[[packages]]
+name = "wrapt"
+version = "1.16.0"
+
+[[packages.wheels]]
+name = "wrapt-1.16.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/21/abdedb4cdf6ff41ebf01a74087740a709e2edb146490e4d9beea054b0b7a/wrapt-1.16.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"
+
+[[packages]]
+name = "wsproto"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "wsproto-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"
+
+[[packages]]
+name = "xarray"
+version = "2025.7.1"
+
+[[packages.wheels]]
+name = "xarray-2025.7.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b2/ea/9554e5fb78eda4dbc9e9ccaf23034166fe3e9ea9af82ea6204b9578434bc/xarray-2025.7.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e8647b659e53bd350d7c5a91c34dd4122ad6a3ca0bc41399d424a7c0273c7635"
+
+[[packages]]
+name = "xlsxwriter"
+version = "3.2.5"
+
+[[packages.wheels]]
+name = "xlsxwriter-3.2.5-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/fa/34/a22e6664211f0c8879521328000bdcae9bf6dbafa94a923e531f6d5b3f73/xlsxwriter-3.2.5-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f4824234e1eaf9d95df9a8fe974585ff91d0f5e3d3f12ace5b71e443c1c6abd"
+
+[[packages]]
+name = "xyzservices"
+version = "2023.10.1"
+
+[[packages.wheels]]
+name = "xyzservices-2023.10.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/82/c3/e06dfa46464cce3eda4b86df8847cab99d9bc545c76807ee689545187a4c/xyzservices-2023.10.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "6a4c38d3a9f89d3e77153eff9414b36a8ee0850c9e8b85796fd1b2a85b8dfd68"
+
+[[packages]]
+name = "yapf"
+version = "0.40.1"
+
+[[packages.wheels]]
+name = "yapf-0.40.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/23/75/c374517c09e31bf22d3b3f156d73e0f38d08e29b2afdd607cef5f1e10aa9/yapf-0.40.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313"
+
+[[packages]]
+name = "yarl"
+version = "1.18.3"
+
+[[packages.wheels]]
+name = "yarl-1.18.3-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"
+
+[[packages]]
+name = "yt-dlp"
+version = "2025.2.19"
+
+[[packages.wheels]]
+name = "yt_dlp-2025.2.19-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9e/45/6d1b759e68f5363b919828fb0e0c167a1cd5003b5b7c74cc0f0c2096be4f/yt_dlp-2025.2.19-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "3ed218eaeece55e9d715afd41abc450dc406ee63bf79355169dfde312d38fdb8"
+
+[[packages]]
+name = "zict"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "zict-3.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/80/ab/11a76c1e2126084fde2639514f24e6111b789b0bfa4fc6264a8975c7e1f1/zict-3.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "5796e36bd0e0cc8cf0fbc1ace6a68912611c1dbd74750a3f3026b9b9d6a327ae"
+
+[[packages]]
+name = "zipp"
+version = "3.21.0"
+
+[[packages.wheels]]
+name = "zipp-3.21.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b7/1a/7e4798e9339adc931158c9d69ecc34f5e6791489d469f5e50ec15e35f458/zipp-3.21.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"
+
+[[packages]]
+name = "zstandard"
+version = "0.23.0"
+
+[[packages.wheels]]
+name = "zstandard-0.23.0-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/a2/bf/c6aaba098e2d04781e8f4f7c0ba3c7aa73d00e4c436bcc0cf059a66691d1/zstandard-0.23.0-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b"
diff --git a/winpython/portable/cycle_2025_04/pylock.64-3_14_0_1dotb3.toml b/winpython/portable/cycle_2025_04/pylock.64-3_14_0_1dotb3.toml
new file mode 100644
index 00000000..e0aac7a6
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/pylock.64-3_14_0_1dotb3.toml
@@ -0,0 +1,101 @@
+lock-version = "1.0"
+created-by = "pip"
+
+[[packages]]
+name = "build"
+version = "1.2.2.post1"
+
+[[packages.wheels]]
+name = "build-1.2.2.post1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"
+
+[[packages]]
+name = "colorama"
+version = "0.4.6"
+
+[[packages.wheels]]
+name = "colorama-0.4.6-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
+
+[[packages]]
+name = "packaging"
+version = "25.0"
+
+[[packages.wheels]]
+name = "packaging-25.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"
+
+[[packages]]
+name = "pyproject-hooks"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "pyproject_hooks-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"
+
+[[packages]]
+name = "setuptools"
+version = "80.9.0"
+
+[[packages.wheels]]
+name = "setuptools-80.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"
+
+[[packages]]
+name = "sqlite-bro"
+version = "0.13.1"
+
+[[packages.wheels]]
+name = "sqlite_bro-0.13.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/b3/81b91f5b26fff329c59dbf826a87637bd51d1903120427912322f86e7d33/sqlite_bro-0.13.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d"
+
+[[packages]]
+name = "sv-ttk"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "sv_ttk-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/3d/be0abc3202e90f282ad465f4e7c6e41bc8dce810ce5d1611566a1e7dfba8/sv_ttk-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"
+
+[[packages]]
+name = "wheel"
+version = "0.45.1"
+
+[[packages.wheels]]
+name = "wheel-0.45.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"
+
+[[packages]]
+name = "wppm"
+version = "17.2.20250823"
+
+[[packages.wheels]]
+name = "wppm-17.2.20250823-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ae/a9/2581cc7f91354eada41367bf68b91b1b7fba6cb6fb469f500dbaf6191539/wppm-17.2.20250823-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3"
diff --git a/winpython/portable/cycle_2025_04/pylock.64-3_14_0_1freeb3.toml b/winpython/portable/cycle_2025_04/pylock.64-3_14_0_1freeb3.toml
new file mode 100644
index 00000000..e0aac7a6
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/pylock.64-3_14_0_1freeb3.toml
@@ -0,0 +1,101 @@
+lock-version = "1.0"
+created-by = "pip"
+
+[[packages]]
+name = "build"
+version = "1.2.2.post1"
+
+[[packages.wheels]]
+name = "build-1.2.2.post1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"
+
+[[packages]]
+name = "colorama"
+version = "0.4.6"
+
+[[packages.wheels]]
+name = "colorama-0.4.6-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
+
+[[packages]]
+name = "packaging"
+version = "25.0"
+
+[[packages.wheels]]
+name = "packaging-25.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"
+
+[[packages]]
+name = "pyproject-hooks"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "pyproject_hooks-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"
+
+[[packages]]
+name = "setuptools"
+version = "80.9.0"
+
+[[packages.wheels]]
+name = "setuptools-80.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"
+
+[[packages]]
+name = "sqlite-bro"
+version = "0.13.1"
+
+[[packages.wheels]]
+name = "sqlite_bro-0.13.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/b3/81b91f5b26fff329c59dbf826a87637bd51d1903120427912322f86e7d33/sqlite_bro-0.13.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d"
+
+[[packages]]
+name = "sv-ttk"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "sv_ttk-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/3d/be0abc3202e90f282ad465f4e7c6e41bc8dce810ce5d1611566a1e7dfba8/sv_ttk-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"
+
+[[packages]]
+name = "wheel"
+version = "0.45.1"
+
+[[packages.wheels]]
+name = "wheel-0.45.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"
+
+[[packages]]
+name = "wppm"
+version = "17.2.20250823"
+
+[[packages.wheels]]
+name = "wppm-17.2.20250823-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ae/a9/2581cc7f91354eada41367bf68b91b1b7fba6cb6fb469f500dbaf6191539/wppm-17.2.20250823-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3"
diff --git a/winpython/portable/cycle_2025_04/pylock.wppmbuild.toml b/winpython/portable/cycle_2025_04/pylock.wppmbuild.toml
new file mode 100644
index 00000000..af5bd953
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/pylock.wppmbuild.toml
@@ -0,0 +1,376 @@
+lock-version = "1.0"
+created-by = "pip"
+
+[[packages]]
+name = "build"
+version = "1.2.2.post1"
+
+[[packages.wheels]]
+name = "build-1.2.2.post1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"
+
+[[packages]]
+name = "certifi"
+version = "2025.4.26"
+
+[[packages.wheels]]
+name = "certifi-2025.4.26-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"
+
+[[packages]]
+name = "charset-normalizer"
+version = "3.4.2"
+
+[[packages.wheels]]
+name = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"
+
+[[packages]]
+name = "colorama"
+version = "0.4.6"
+
+[[packages.wheels]]
+name = "colorama-0.4.6-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
+
+[[packages]]
+name = "docutils"
+version = "0.21.2"
+
+[[packages.wheels]]
+name = "docutils-0.21.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"
+
+[[packages]]
+name = "flit"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "flit-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f5/82/ce1d3bb380b227e26e517655d1de7b32a72aad61fa21ff9bd91a2e2db6ee/flit-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2b4e7171dc22881fa6adc2dbf083e5ecc72520be3cd7587d2a803da94d6ef431"
+
+[[packages]]
+name = "flit-core"
+version = "3.12.0"
+
+[[packages.wheels]]
+name = "flit_core-3.12.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f2/65/b6ba90634c984a4fcc02c7e3afe523fef500c4980fec67cc27536ee50acf/flit_core-3.12.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "e7a0304069ea895172e3c7bb703292e992c5d1555dd1233ab7b5621b5b69e62c"
+
+[[packages]]
+name = "id"
+version = "1.5.0"
+
+[[packages.wheels]]
+name = "id-1.5.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/cb/18326d2d89ad3b0dd143da971e77afd1e6ca6674f1b1c3df4b6bec6279fc/id-1.5.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"
+
+[[packages]]
+name = "idna"
+version = "3.10"
+
+[[packages.wheels]]
+name = "idna-3.10-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
+
+[[packages]]
+name = "jaraco-classes"
+version = "3.4.0"
+
+[[packages.wheels]]
+name = "jaraco.classes-3.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"
+
+[[packages]]
+name = "jaraco-context"
+version = "6.0.1"
+
+[[packages.wheels]]
+name = "jaraco.context-6.0.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"
+
+[[packages]]
+name = "jaraco-functools"
+version = "4.1.0"
+
+[[packages.wheels]]
+name = "jaraco.functools-4.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"
+
+[[packages]]
+name = "keyring"
+version = "25.6.0"
+
+[[packages.wheels]]
+name = "keyring-25.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"
+
+[[packages]]
+name = "markdown-it-py"
+version = "3.0.0"
+
+[[packages.wheels]]
+name = "markdown_it_py-3.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"
+
+[[packages]]
+name = "mdurl"
+version = "0.1.2"
+
+[[packages.wheels]]
+name = "mdurl-0.1.2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"
+
+[[packages]]
+name = "more-itertools"
+version = "10.7.0"
+
+[[packages.wheels]]
+name = "more_itertools-10.7.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e"
+
+[[packages]]
+name = "nh3"
+version = "0.2.21"
+
+[[packages.wheels]]
+name = "nh3-0.2.21-cp38-abi3-win_amd64.whl"
+url = "https://files.pythonhosted.org/packages/23/fc/8ce756c032c70ae3dd1d48a3552577a325475af2a2f629604b44f571165c/nh3-0.2.21-cp38-abi3-win_amd64.whl"
+
+[packages.wheels.hashes]
+sha256 = "bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629"
+
+[[packages]]
+name = "packaging"
+version = "25.0"
+
+[[packages.wheels]]
+name = "packaging-25.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"
+
+[[packages]]
+name = "pygments"
+version = "2.19.1"
+
+[[packages.wheels]]
+name = "pygments-2.19.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"
+
+[[packages]]
+name = "pyproject-hooks"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "pyproject_hooks-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"
+
+[[packages]]
+name = "pywin32-ctypes"
+version = "0.2.3"
+
+[[packages.wheels]]
+name = "pywin32_ctypes-0.2.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"
+
+[[packages]]
+name = "readme-renderer"
+version = "44.0"
+
+[[packages.wheels]]
+name = "readme_renderer-44.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"
+
+[[packages]]
+name = "requests"
+version = "2.32.3"
+
+[[packages.wheels]]
+name = "requests-2.32.3-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
+
+[[packages]]
+name = "requests-toolbelt"
+version = "1.0.0"
+
+[[packages.wheels]]
+name = "requests_toolbelt-1.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"
+
+[[packages]]
+name = "rfc3986"
+version = "2.0.0"
+
+[[packages.wheels]]
+name = "rfc3986-2.0.0-py2.py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"
+
+[[packages]]
+name = "rich"
+version = "14.0.0"
+
+[[packages.wheels]]
+name = "rich-14.0.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"
+
+[[packages]]
+name = "setuptools"
+version = "80.9.0"
+
+[[packages.wheels]]
+name = "setuptools-80.9.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"
+
+[[packages]]
+name = "sqlite-bro"
+version = "0.13.1"
+
+[[packages.wheels]]
+name = "sqlite_bro-0.13.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/2a/b3/81b91f5b26fff329c59dbf826a87637bd51d1903120427912322f86e7d33/sqlite_bro-0.13.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d"
+
+[[packages]]
+name = "sv-ttk"
+version = "2.6.0"
+
+[[packages.wheels]]
+name = "sv_ttk-2.6.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0f/3d/be0abc3202e90f282ad465f4e7c6e41bc8dce810ce5d1611566a1e7dfba8/sv_ttk-2.6.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"
+
+[[packages]]
+name = "tomli-w"
+version = "1.2.0"
+
+[[packages.wheels]]
+name = "tomli_w-1.2.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90"
+
+[[packages]]
+name = "twine"
+version = "6.1.0"
+
+[[packages.wheels]]
+name = "twine-6.1.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/7c/b6/74e927715a285743351233f33ea3c684528a0d374d2e43ff9ce9585b73fe/twine-6.1.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"
+
+[[packages]]
+name = "urllib3"
+version = "2.4.0"
+
+[[packages.wheels]]
+name = "urllib3-2.4.0-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
+
+[[packages]]
+name = "wheel"
+version = "0.45.1"
+
+[[packages.wheels]]
+name = "wheel-0.45.1-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"
+
+[[packages]]
+name = "wppm"
+version = "17.2.20250802b2"
+
+[[packages.wheels]]
+name = "wppm-17.2.20250802b2-py3-none-any.whl"
+url = "https://files.pythonhosted.org/packages/80/7b/07a8203e29fea503b6012a075055fdbc57c4be95739e4a9b7d65ed8ef599/wppm-17.2.20250802b2-py3-none-any.whl"
+
+[packages.wheels.hashes]
+sha256 = "ed916dcefbc2d597a77cc74d459e8661c59584a690a7d4063d60976fb4d1499f"
diff --git a/winpython/portable/cycle_2025_04/requir.64-3_13_7_0dotb3.txt b/winpython/portable/cycle_2025_04/requir.64-3_13_7_0dotb3.txt
new file mode 100644
index 00000000..8f1d0eee
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/requir.64-3_13_7_0dotb3.txt
@@ -0,0 +1,18 @@
+build==1.2.2.post1 \
+ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5
+colorama==0.4.6 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+packaging==25.0 \
+ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484
+pyproject-hooks==1.2.0 \
+ --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
+setuptools==80.9.0 \
+ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922
+sqlite-bro==0.13.1 \
+ --hash=sha256:c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d
+sv-ttk==2.6.0 \
+ --hash=sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9
+wheel==0.45.1 \
+ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
+wppm==17.2.20250823 \
+ --hash=sha256:0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3
diff --git a/winpython/portable/cycle_2025_04/requir.64-3_13_7_0slimb3.txt b/winpython/portable/cycle_2025_04/requir.64-3_13_7_0slimb3.txt
new file mode 100644
index 00000000..9a72727f
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/requir.64-3_13_7_0slimb3.txt
@@ -0,0 +1,1012 @@
+absl-py==2.3.0 \
+ --hash=sha256:9824a48b654a306168f63e0d97714665f8490b8d89ec7bf2efc24bf67cf579b3
+adbc-driver-manager==1.6.0 \
+ --hash=sha256:0e8ffb182fafe1e6ae12964a833700daacc55f7abfdc2ada8b5214b18108d87b
+aiofiles==24.1.0 \
+ --hash=sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5
+aiohappyeyeballs==2.6.1 \
+ --hash=sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8
+aiohttp==3.11.18 \
+ --hash=sha256:bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01
+aiosignal==1.3.2 \
+ --hash=sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5
+aiosqlite==0.21.0 \
+ --hash=sha256:2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0
+alabaster==1.0.0 \
+ --hash=sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b
+alembic==1.16.1 \
+ --hash=sha256:0cdd48acada30d93aa1035767d67dff25702f8de74d7c3919f2e8492c8db2e67
+altair==5.5.0 \
+ --hash=sha256:91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c
+annotated-types==0.7.0 \
+ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53
+ansicolors==1.1.8 \
+ --hash=sha256:00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187
+anthropic==0.64.0 \
+ --hash=sha256:6f5f7d913a6a95eb7f8e1bda4e75f76670e8acd8d4cd965e02e2a256b0429dd1
+anyio==4.9.0 \
+ --hash=sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c
+anywidget==0.9.18 \
+ --hash=sha256:944b82ef1dd17b8ff0fb6d1f199f613caf9111338e6e2857da478f6e73770cb8
+appdirs==1.4.4 \
+ --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128
+argcomplete==3.6.2 \
+ --hash=sha256:65b3133a29ad53fb42c48cf5114752c7ab66c1c38544fdf6460f450c09b42591
+argon2-cffi==25.1.0 \
+ --hash=sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741
+argon2-cffi-bindings==21.2.0 \
+ --hash=sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f
+array-api-compat==1.12.0 \
+ --hash=sha256:a0b4795b6944a9507fde54679f9350e2ad2b1e2acf4a2408a098cdc27f890a8b
+arrow==1.3.0 \
+ --hash=sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80
+asgi-csrf==0.11 \
+ --hash=sha256:03ac140115f39d4295288a9adf74fdc6ae607f6ef44abee8466520458207242b
+asgiref==3.8.1 \
+ --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47
+asn1crypto==1.5.1 \
+ --hash=sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67
+asteval==1.0.5 \
+ --hash=sha256:082b95312578affc8a6d982f7d92b7ac5de05634985c87e7eedd3188d31149fa
+astroid==3.3.9 \
+ --hash=sha256:d05bfd0acba96a7bd43e222828b7d9bc1e138aaeb0649707908d3702a9831248
+astropy==7.1.0 \
+ --hash=sha256:8e317f34e33a8f5517bc9fc6fbc005f42730d3be7d2820ef41e0468bcb796843
+astropy-iers-data==0.2025.6.9.0.39.3 \
+ --hash=sha256:76855f5572707b8d25f77a0ede2b330b7ef9863bc963e3eda86321e4e32df802
+asttokens==3.0.0 \
+ --hash=sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2
+async-lru==2.0.5 \
+ --hash=sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943
+asyncssh==2.21.0 \
+ --hash=sha256:cf7f3dfa52b2cb4ad31f0d77ff0d0a8fdd850203da84a0e72e62c36fdd4daf4b
+atomicwrites==1.4.0 \
+ --hash=sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197
+attrs==25.3.0 \
+ --hash=sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3
+autopep8==2.0.4 \
+ --hash=sha256:067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb
+azure-core==1.34.0 \
+ --hash=sha256:0615d3b756beccdb6624d1c0ae97284f38b78fb59a2a9839bf927c66fbbdddd6
+azure-cosmos==4.9.0 \
+ --hash=sha256:3b60eaa01a16a857d0faf0cec304bac6fa8620a81bc268ce760339032ef617fe
+azure-identity==1.23.0 \
+ --hash=sha256:dbbeb64b8e5eaa81c44c565f264b519ff2de7ff0e02271c49f3cb492762a50b0
+babel==2.17.0 \
+ --hash=sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2
+baresql==1.0.0 \
+ --hash=sha256:a24d17f46beb47c221f328f7e06710e3896c6203a8e1909788d7128f27b86f01
+bcrypt==4.3.0 \
+ --hash=sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b
+beautifulsoup4==4.13.4 \
+ --hash=sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b
+binaryornot==0.4.4 \
+ --hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4
+black==25.1.0 \
+ --hash=sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18
+bleach==6.2.0 \
+ --hash=sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e
+blinker==1.9.0 \
+ --hash=sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc
+bokeh==3.7.3 \
+ --hash=sha256:b0e79dd737f088865212e4fdcb0f3b95d087f0f088bf8ca186a300ab1641e2c7
+branca==0.8.1 \
+ --hash=sha256:d29c5fab31f7c21a92e34bf3f854234e29fecdcf5d2df306b616f20d816be425
+brotli==1.1.0 \
+ --hash=sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b
+build==1.2.2.post1 \
+ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5
+cachetools==5.5.2 \
+ --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a
+certifi==2025.4.26 \
+ --hash=sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3
+cffi==1.17.1 \
+ --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a
+chardet==5.2.0 \
+ --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+charset-normalizer==3.4.2 \
+ --hash=sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980
+clarabel==0.10.0 \
+ --hash=sha256:7871b6f499ad66f71d4e7fb40754c4d986d4316f242beb62ff4f63a69785a50c
+click==8.2.1 \
+ --hash=sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b
+click-default-group==1.2.4 \
+ --hash=sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f
+cloudpickle==3.1.1 \
+ --hash=sha256:c8c5a44295039331ee9dad40ba100a9c7297b6f988e50e87ccdf3765a668350e
+cohere==5.16.1 \
+ --hash=sha256:37e2c1d69b1804071b5e5f5cb44f8b74127e318376e234572d021a1a729c6baa
+colorama==0.4.6 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+colorcet==3.1.0 \
+ --hash=sha256:2a7d59cc8d0f7938eeedd08aad3152b5319b4ba3bcb7a612398cc17a384cb296
+coloredlogs==7.3.1 \
+ --hash=sha256:f08ee2a2cef08163ddd24596e48cba2243937abf915d7fb37d62254596b816a9
+colorlog==6.9.0 \
+ --hash=sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff
+comm==0.2.2 \
+ --hash=sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3
+contourpy==1.3.2 \
+ --hash=sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9
+cookiecutter==2.6.0 \
+ --hash=sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d
+cryptography==45.0.5 \
+ --hash=sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63
+cvxopt==1.3.2 \
+ --hash=sha256:0a0987966009ad383de0918e61255d34ed9ebc783565bcb15470d4155010b6bf
+cvxpy==1.6.5 \
+ --hash=sha256:51161b0e8b0d83dc07355bab938bd0734dd5531c98dca8d6faaa8b847c651339
+cycler==0.12.1 \
+ --hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30
+cython==3.1.2 \
+ --hash=sha256:8ab1319c77f15b0ae04b3fb03588df3afdec4cf79e90eeea5c961e0ebd8fdf72
+cytoolz==1.0.1 \
+ --hash=sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297
+dask==2025.7.0 \
+ --hash=sha256:073c29c4e99c2400a39a8a67874f35c1d15bf7af9ae3d0c30af3c7c1199f24ae
+datasette==0.65.1 \
+ --hash=sha256:ba7adf717ddcc24a2a8ac57890fffd384a2ebb909b342e4f731ba09eba764305
+datasette-graphql==2.2 \
+ --hash=sha256:cd9f61afdcaab1ce4ff6775296e6ece99305bf05cbfae4c1c938a6c9e60cd485
+datashader==0.18.1 \
+ --hash=sha256:5585af146e83af51c61d49168a741a6280a482072572e16573af1e5c6b600f8a
+deap==1.4.2 \
+ --hash=sha256:1abab976c75b0f18c36e81f968fcc77fac69fc9bedbab8be3323ca376f6fcfa4
+debugpy==1.8.14 \
+ --hash=sha256:684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e
+decorator==5.2.1 \
+ --hash=sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a
+defusedxml==0.7.1 \
+ --hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
+deprecated==1.2.18 \
+ --hash=sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec
+diff-match-patch==20241021 \
+ --hash=sha256:93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782
+dill==0.4.0 \
+ --hash=sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049
+distributed==2025.7.0 \
+ --hash=sha256:51b74526c2bee409ca968ee5532c79de1c1a1713664f5ccf90bdd81f17cfdc73
+distro==1.9.0 \
+ --hash=sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2
+django==5.2.1 \
+ --hash=sha256:a9b680e84f9a0e71da83e399f1e922e1ab37b2173ced046b541c72e1589a5961
+dnspython==2.7.0 \
+ --hash=sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86
+docstring-to-markdown==0.17 \
+ --hash=sha256:fd7d5094aa83943bf5f9e1a13701866b7c452eac19765380dead666e36d3711c
+docutils==0.21.2 \
+ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
+duckdb==1.3.0 \
+ --hash=sha256:fbdfc1c0b83b90f780ae74038187ee696bb56ab727a289752372d7ec42dda65b
+entrypoints==0.4 \
+ --hash=sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f
+et-xmlfile==2.0.0 \
+ --hash=sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa
+eval-type-backport==0.2.2 \
+ --hash=sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a
+executing==2.2.0 \
+ --hash=sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa
+faker==37.3.0 \
+ --hash=sha256:48c94daa16a432f2d2bc803c7ff602509699fca228d13e97e379cd860a7e216e
+fasta2a==0.2.9 \
+ --hash=sha256:8b855b36f29fde6dcb79ad55be337a8165381b679bec829913009c55581e284e
+fastapi==0.115.12 \
+ --hash=sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d
+fastavro==1.11.1 \
+ --hash=sha256:cde7ed91b52ff21f0f9f157329760ba7251508ca3e9618af3ffdac986d9faaa2
+fastjsonschema==2.21.1 \
+ --hash=sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667
+filelock==3.18.0 \
+ --hash=sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de
+flake8==7.1.1 \
+ --hash=sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213
+flask==3.1.1 \
+ --hash=sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c
+flatbuffers==25.2.10 \
+ --hash=sha256:ebba5f4d5ea615af3f7fd70fc310636fbb2bbd1f566ac0a23d98dd412de50051
+flexcache==0.3 \
+ --hash=sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32
+flexparser==0.4 \
+ --hash=sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846
+flit==3.12.0 \
+ --hash=sha256:2b4e7171dc22881fa6adc2dbf083e5ecc72520be3cd7587d2a803da94d6ef431
+flit-core==3.12.0 \
+ --hash=sha256:e7a0304069ea895172e3c7bb703292e992c5d1555dd1233ab7b5621b5b69e62c
+folium==0.19.5 \
+ --hash=sha256:4333fb3e6f3e9eedb231615d22c6d7df20aea5829554bd6908675865a37803b3
+fonttools==4.58.5 \
+ --hash=sha256:bca61b14031a4b7dc87e14bf6ca34c275f8e4b9f7a37bc2fe746b532a924cf30
+fqdn==1.5.1 \
+ --hash=sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014
+frozenlist==1.7.0 \
+ --hash=sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba
+fsspec==2025.5.1 \
+ --hash=sha256:24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462
+fuzzywuzzy==0.18.0 \
+ --hash=sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993
+geographiclib==2.0 \
+ --hash=sha256:6b7225248e45ff7edcee32becc4e0a1504c606ac5ee163a5656d482e0cd38734
+geopandas==1.0.1 \
+ --hash=sha256:01e147d9420cc374d26f51fc23716ac307f32b49406e4bd8462c07e82ed1d3d6
+geopy==2.4.1 \
+ --hash=sha256:ae8b4bc5c1131820f4d75fce9d4aaaca0c85189b3aa5d64c3dcaf5e3b7b882a7
+gitdb==4.0.12 \
+ --hash=sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf
+gitpython==3.1.44 \
+ --hash=sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110
+google-auth==2.40.3 \
+ --hash=sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca
+google-genai==1.20.0 \
+ --hash=sha256:ccd61d6ebcb14f5c778b817b8010e3955ae4f6ddfeaabf65f42f6d5e3e5a8125
+graphene==3.4.3 \
+ --hash=sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71
+graphql-core==3.2.6 \
+ --hash=sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f
+graphql-relay==3.2.0 \
+ --hash=sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5
+greenlet==3.2.3 \
+ --hash=sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3
+griffe==1.7.3 \
+ --hash=sha256:c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75
+groq==0.28.0 \
+ --hash=sha256:c6f86638371c2cba2ca337232e76c8d412e75965ed7e3058d30c9aa5dfe84303
+guidata==3.12.0 \
+ --hash=sha256:8cc05220126dfdd562281de9e761b0c279a4112d699bff55d4b17d95d7bfa1d1
+h11==0.16.0 \
+ --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
+h2==4.2.0 \
+ --hash=sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0
+h5py==3.12.1 \
+ --hash=sha256:52ab036c6c97055b85b2a242cb540ff9590bacfda0c03dd0cf0661b311f522f8
+hatchling==1.27.0 \
+ --hash=sha256:d3a2f3567c4f926ea39849cdf924c7e99e6686c9c8e288ae1037c8fa2a5d937b
+holoviews==1.20.2 \
+ --hash=sha256:1f892c04bc23e8a3a9cde082b606b9463c9ff78c3d0c00e2ddcc41fe6e738458
+hpack==4.1.0 \
+ --hash=sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496
+html5lib==1.1 \
+ --hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d
+httpcore==1.0.9 \
+ --hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55
+httpie==3.2.4 \
+ --hash=sha256:4bd0435cc4b9bca59501bc65089de96f3e93b393803f32a81951db62050ebf0b
+httpx==0.28.1 \
+ --hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
+httpx-sse==0.4.0 \
+ --hash=sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f
+huggingface-hub==0.34.4 \
+ --hash=sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a
+humanfriendly==10.0 \
+ --hash=sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477
+hupper==1.12.1 \
+ --hash=sha256:e872b959f09d90be5fb615bd2e62de89a0b57efc037bdf9637fb09cdf8552b19
+hvplot==0.11.3 \
+ --hash=sha256:5fa236a737ef3ca83870bf1b481218855834f4fad56ed0cb041ce5f2792cc7a3
+hypercorn==0.17.3 \
+ --hash=sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547
+hyperframe==6.1.0 \
+ --hash=sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5
+hypothesis==6.135.4 \
+ --hash=sha256:6a3b13ce35d43e14aaf6a6ca4cc411e5342be5d05b77977499d07cf6a61e6e71
+id==1.5.0 \
+ --hash=sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658
+idna==3.10 \
+ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
+imageio==2.37.0 \
+ --hash=sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b
+importlib-metadata==8.7.0 \
+ --hash=sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd
+inflection==0.5.1 \
+ --hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2
+iniconfig==2.1.0 \
+ --hash=sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760
+intervaltree==3.1.0 \
+ --hash=sha256:902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d
+ipycanvas==0.13.3 \
+ --hash=sha256:d37adb2f45d2fef1c3d33c69a0518055694d87827b2f577f3c426d7712f75daa
+ipykernel==6.29.5 \
+ --hash=sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5
+ipyleaflet==0.20.0 \
+ --hash=sha256:b4c20ddc0b17d68e226cd3367ca2215a4db7e2b14374468c0eeaa54b53e4d173
+ipympl==0.9.7 \
+ --hash=sha256:3698ee7eaa0b047a7603517d7aa1b71b32118a5f51754cab45ec5d994f67208f
+ipython==8.37.0 \
+ --hash=sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2
+ipython-genutils==0.2.0 \
+ --hash=sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8
+ipython-sql==0.5.0 \
+ --hash=sha256:61b46ecffb956f62dbc17b5744cf70c649104c8db9afd821aa39b31f7cbb5d5b
+ipywidgets==8.1.7 \
+ --hash=sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb
+isoduration==20.11.0 \
+ --hash=sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042
+isort==6.0.1 \
+ --hash=sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615
+itsdangerous==2.2.0 \
+ --hash=sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef
+janus==2.0.0 \
+ --hash=sha256:7e6449d34eab04cd016befbd7d8c0d8acaaaab67cb59e076a69149f9031745f9
+jaraco-classes==3.4.0 \
+ --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790
+jaraco-context==6.0.1 \
+ --hash=sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4
+jaraco-functools==4.2.1 \
+ --hash=sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e
+jedi==0.19.2 \
+ --hash=sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9
+jellyfish==1.2.0 \
+ --hash=sha256:c8089e918ddb1abae946e92d053f646a7f686d0d051ef69cdfaa28b37352bbdf
+jinja2==3.1.6 \
+ --hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
+jiter==0.10.0 \
+ --hash=sha256:75f9eb72ecb640619c29bf714e78c9c46c9c4eaafd644bf78577ede459f330d4
+joblib==1.5.1 \
+ --hash=sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a
+json5==0.12.0 \
+ --hash=sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db
+jsonpatch==1.33 \
+ --hash=sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade
+jsonpointer==3.0.0 \
+ --hash=sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942
+jsonschema==4.24.0 \
+ --hash=sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d
+jsonschema-specifications==2025.4.1 \
+ --hash=sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af
+julia==0.6.2 \
+ --hash=sha256:90752f71376fdb9919439d20496c2dab24486dfa4fe8a831d6dd14a1bcbc04d1
+jupyter==1.1.1 \
+ --hash=sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83
+jupyter-bokeh==4.0.5 \
+ --hash=sha256:1110076c14c779071cf492646a1a871aefa8a477261e4721327a666e65df1a2c
+jupyter-client==8.6.3 \
+ --hash=sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f
+jupyter-console==6.6.3 \
+ --hash=sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485
+jupyter-core==5.8.1 \
+ --hash=sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0
+jupyter-events==0.12.0 \
+ --hash=sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb
+jupyter-leaflet==0.20.0 \
+ --hash=sha256:2e27ce83647316424f04845e3a6af35e1ee44c177c318a145646b11f4afe0764
+jupyter-lsp==2.2.5 \
+ --hash=sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da
+jupyter-server==2.16.0 \
+ --hash=sha256:3d8db5be3bc64403b1c65b400a1d7f4647a5ce743f3b20dbdefe8ddb7b55af9e
+jupyter-server-terminals==0.5.3 \
+ --hash=sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa
+jupyterlab==4.4.4 \
+ --hash=sha256:711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd
+jupyterlab-pygments==0.3.0 \
+ --hash=sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780
+jupyterlab-server==2.27.3 \
+ --hash=sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4
+jupyterlab-widgets==3.0.15 \
+ --hash=sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c
+keras==3.11.3 \
+ --hash=sha256:f484f050e05ee400455b05ec8c36ed35edc34de94256b6073f56cfe68f65491f
+keyring==25.6.0 \
+ --hash=sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd
+kiwisolver==1.4.8 \
+ --hash=sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2
+langchain==0.3.27 \
+ --hash=sha256:7b20c4f338826acb148d885b20a73a16e410ede9ee4f19bb02011852d5f98798
+langchain-core==0.3.72 \
+ --hash=sha256:9fa15d390600eb6b6544397a7aa84be9564939b6adf7a2b091179ea30405b240
+langchain-text-splitters==0.3.9 \
+ --hash=sha256:cee0bb816211584ea79cc79927317c358543f40404bcfdd69e69ba3ccde54401
+langsmith==0.4.8 \
+ --hash=sha256:ca2f6024ab9d2cd4d091b2e5b58a5d2cb0c354a0c84fe214145a89ad450abae0
+lazy-loader==0.4 \
+ --hash=sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc
+linkify-it-py==2.0.3 \
+ --hash=sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79
+llvmlite==0.44.0 \
+ --hash=sha256:2fb7c4f2fb86cbae6dca3db9ab203eeea0e22d73b99bc2341cdf9de93612e930
+lmfit==1.3.3 \
+ --hash=sha256:a9e9ec7d0d0ec962cc6c078ad1ec6c8311d3ac0e5f0947a00a91f5509dacc2b2
+locket==1.0.0 \
+ --hash=sha256:b6c819a722f7b6bd955b80781788e4a66a55628b858d347536b7e81325a3a5e3
+logfire-api==3.12.0 \
+ --hash=sha256:fc092c2dcb24c8462ba776f3b0c2183f82e1cd55f86e29b38cf21a048e66a17d
+lxml==6.0.0 \
+ --hash=sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e
+magika==0.6.2 \
+ --hash=sha256:711f427a633e0182737dcc2074748004842f870643585813503ff2553b973b9f
+mako==1.3.10 \
+ --hash=sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59
+markdown==3.7 \
+ --hash=sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803
+markdown-it-py==3.0.0 \
+ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1
+markdownify==1.1.0 \
+ --hash=sha256:32a5a08e9af02c8a6528942224c91b933b4bd2c7d078f9012943776fc313eeef
+markitdown==0.1.2 \
+ --hash=sha256:4881f0768794ffccb52d09dd86498813a6896ba9639b4fc15512817f56ed9d74
+markupsafe==3.0.2 \
+ --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f
+matplotlib==3.10.5 \
+ --hash=sha256:07442d2692c9bd1cceaa4afb4bbe5b57b98a7599de4dabfcca92d3eea70f9ebe
+matplotlib-inline==0.1.7 \
+ --hash=sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca
+maturin==1.9.0 \
+ --hash=sha256:fb9796c1893d1e3cd9da9325ef3c63d54a5b0fe6183ddae4954b10c64a1ae5e3
+mccabe==0.7.0 \
+ --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
+mcp==1.9.3 \
+ --hash=sha256:69b0136d1ac9927402ed4cf221d4b8ff875e7132b0b06edd446448766f34f9b9
+mdit-py-plugins==0.4.2 \
+ --hash=sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636
+mdurl==0.1.2 \
+ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8
+mercantile==1.2.1 \
+ --hash=sha256:30f457a73ee88261aab787b7069d85961a5703bb09dc57a170190bc042cd023f
+mergedeep==1.3.4 \
+ --hash=sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307
+missingno==0.5.2 \
+ --hash=sha256:55782621ce09ba0f0a1d08e5bd6d6fe1946469fb03951fadf7d209911ca5b072
+mistralai==1.9.3 \
+ --hash=sha256:962445e7cebadcbfbcd1daf973e853a832dcf7aba6320468fcf7e2cf5f943aec
+mistune==3.1.3 \
+ --hash=sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9
+mizani==0.11.4 \
+ --hash=sha256:5b6271dc3da2c88694dca2e0e0a7e1879f0e2fb046c789776f54d090a5243735
+ml-dtypes==0.5.1 \
+ --hash=sha256:fd918d4e6a4e0c110e2e05be7a7814d10dc1b95872accbf6512b80a109b71ae1
+mlxtend==0.23.3 \
+ --hash=sha256:f9fec721c4121be87dac00e513456dde5bf56b7427750719c0a291cd58b6538e
+more-itertools==10.7.0 \
+ --hash=sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e
+mpld3==0.5.10 \
+ --hash=sha256:80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1
+mpmath==1.3.0 \
+ --hash=sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c
+msal==1.32.3 \
+ --hash=sha256:b2798db57760b1961b142f027ffb7c8169536bf77316e99a0df5c4aaebb11569
+msal-extensions==1.3.1 \
+ --hash=sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca
+msgpack==1.1.0 \
+ --hash=sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f
+multidict==6.4.4 \
+ --hash=sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373
+multipledispatch==1.0.0 \
+ --hash=sha256:0c53cd8b077546da4e48869f49b13164bebafd0c2a5afceb6bb6a316e7fb46e4
+mypy==1.16.1 \
+ --hash=sha256:4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee
+mypy-extensions==1.1.0 \
+ --hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505
+mysql-connector-python==9.2.0 \
+ --hash=sha256:6557942f6c6be3b41d2965456b53a244a7ce3e6fb81cb195c243549be72a6a24
+namex==0.1.0 \
+ --hash=sha256:e2012a474502f1e2251267062aae3114611f07df4224b6e06334c57b0f2ce87c
+narwhals==2.0.1 \
+ --hash=sha256:837457e36a2ba1710c881fb69e1f79ce44fb81728c92ac378f70892a53af8ddb
+nbclient==0.10.2 \
+ --hash=sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d
+nbconvert==7.16.6 \
+ --hash=sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b
+nbformat==5.10.4 \
+ --hash=sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b
+nest-asyncio==1.6.0 \
+ --hash=sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c
+networkx==3.5 \
+ --hash=sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec
+nh3==0.2.21 \
+ --hash=sha256:bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629
+nltk==3.9.1 \
+ --hash=sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1
+notebook==7.4.2 \
+ --hash=sha256:9ccef602721aaa5530852e3064710b8ae5415c4e2ce26f8896d0433222755259
+notebook-shim==0.2.4 \
+ --hash=sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef
+numba==0.61.2 \
+ --hash=sha256:59321215e2e0ac5fa928a8020ab00b8e57cda8a97384963ac0dfa4d4e6aa54e7
+numpy==2.2.6 \
+ --hash=sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c
+numpydoc==1.8.0 \
+ --hash=sha256:72024c7fd5e17375dec3608a27c03303e8ad00c81292667955c6fea7a3ccf541
+onnxruntime==1.22.1 \
+ --hash=sha256:70980d729145a36a05f74b573435531f55ef9503bcda81fc6c3d6b9306199982
+openai==1.101.0 \
+ --hash=sha256:6539a446cce154f8d9fb42757acdfd3ed9357ab0d34fcac11096c461da87133b
+opencv-python==4.11.0.86 \
+ --hash=sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec
+openpyxl==3.1.5 \
+ --hash=sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2
+opentelemetry-api==1.34.1 \
+ --hash=sha256:b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c
+optree==0.14.1 \
+ --hash=sha256:25ea23fc6d6c0fa7dcf85afcfe10b43ed4fdf0e9d958a3677cd27fcdf0ca17d6
+optuna==4.2.1 \
+ --hash=sha256:6d38199013441d3f70fac27136e05c0188c5f4ec3848db708ac311cbdeb30dbf
+orjson==3.10.18 \
+ --hash=sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52
+osqp==0.6.7.post3 \
+ --hash=sha256:acb219e941f5248da5de3ee9b70e6a5aaddf5f3989dffd1d4c03b0f7b1dfa17b
+outcome==1.3.0.post0 \
+ --hash=sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b
+overrides==7.7.0 \
+ --hash=sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49
+packaging==25.0 \
+ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484
+pandas==2.3.1 \
+ --hash=sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956
+pandocfilters==1.5.1 \
+ --hash=sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc
+panel==1.6.3 \
+ --hash=sha256:ccd2a0587ab382bd55b8ea099706f31b64aadac697b8a41923d3b18b9ed618d6
+papermill==2.6.0 \
+ --hash=sha256:0f09da6ef709f3f14dde77cb1af052d05b14019189869affff374c9e612f2dd5
+param==2.2.0 \
+ --hash=sha256:777f8c7b66ab820b70ea5ad09faaa6818308220caae89da3b5c5f359faa72a5e
+parso==0.8.4 \
+ --hash=sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18
+partd==1.4.2 \
+ --hash=sha256:978e4ac767ec4ba5b86c6eaa52e5a2a3bc748a2ca839e8cc798f1cc6ce6efb0f
+pathspec==0.12.1 \
+ --hash=sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08
+patsy==1.0.1 \
+ --hash=sha256:751fb38f9e97e62312e921a1954b81e1bb2bcda4f5eeabaf94db251ee791509c
+pep8==1.7.1 \
+ --hash=sha256:b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee
+pexpect==4.9.0 \
+ --hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523
+pg8000==1.31.2 \
+ --hash=sha256:436c771ede71af4d4c22ba867a30add0bc5c942d7ab27fadbb6934a487ecc8f6
+pickleshare==0.7.5 \
+ --hash=sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56
+pillow==11.3.0 \
+ --hash=sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51
+platformdirs==4.3.7 \
+ --hash=sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94
+plotly==6.2.0 \
+ --hash=sha256:32c444d4c940887219cb80738317040363deefdfee4f354498cc0b6dab8978bd
+plotnine==0.13.6 \
+ --hash=sha256:4acc1af29fa4e91e726b67d49277e8368f62e1c817f01bf14ecd8ca5e83bfaea
+plotpy==2.7.4 \
+ --hash=sha256:8dff5fd388048a8d3b4251329a9fe4027920386e0ebcc3c3642f59c432118c29
+pluggy==1.5.0 \
+ --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669
+ply==3.11 \
+ --hash=sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce
+polars==1.32.2 \
+ --hash=sha256:5e1660a584e89e1d60cd89984feca38a695e491a966581fefe8be99c230ea154
+prettytable==3.16.0 \
+ --hash=sha256:b5eccfabb82222f5aa46b798ff02a8452cf530a352c31bddfa29be41242863aa
+prince==0.16.0 \
+ --hash=sha256:7e21a78d4dd06ca3ec526ee714a50b349f26de3fca6b79664150a951b31688f3
+priority==2.0.0 \
+ --hash=sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa
+prometheus-client==0.21.1 \
+ --hash=sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301
+prompt-toolkit==3.0.51 \
+ --hash=sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07
+propcache==0.3.1 \
+ --hash=sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037
+protobuf==6.30.2 \
+ --hash=sha256:7653c99774f73fe6b9301b87da52af0e69783a2e371e8b599b3e9cb4da4b12b9
+psutil==7.0.0 \
+ --hash=sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553
+psygnal==0.12.0 \
+ --hash=sha256:d779f20c6977ec9d5b9fece23b4b28bbcf0a7773539a4a176b5527aea5da27c7
+ptpython==3.0.30 \
+ --hash=sha256:bec3045f0285ac817c902ef98d6ece31d3e00a4604ef3fdde07d365c78bde23c
+ptyprocess==0.7.0 \
+ --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35
+pure-eval==0.2.3 \
+ --hash=sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0
+pyarrow==21.0.0 \
+ --hash=sha256:186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636
+pyasn1==0.6.1 \
+ --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629
+pyasn1-modules==0.4.1 \
+ --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd
+pybind11==3.0.0 \
+ --hash=sha256:7c5cac504da5a701b5163f0e6a7ba736c713a096a5378383c5b4b064b753f607
+pycodestyle==2.12.0 \
+ --hash=sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4
+pycparser==2.22 \
+ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
+pyct==0.5.0 \
+ --hash=sha256:a4038a8885059ab8cac6f946ea30e0b5e6bdbe0b92b6723f06737035f9d65e8c
+pydantic==2.11.7 \
+ --hash=sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b
+pydantic-ai-slim==0.2.9 \
+ --hash=sha256:d954ff84cb250d7150a7ed694e4f1f92f820205d036ee006d02fce3e62a3bc4e
+pydantic-core==2.33.2 \
+ --hash=sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9
+pydantic-evals==0.2.9 \
+ --hash=sha256:62035ae3a5321e4d892c7372ef91af0f46b675863e827f011d5cb8550dede400
+pydantic-graph==0.2.9 \
+ --hash=sha256:38ad929a0ec205bd7d5875b0b408d4f13448276aa89b6ce2a1143a7552b070ce
+pydantic-settings==2.8.1 \
+ --hash=sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c
+pydeck==0.9.1 \
+ --hash=sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038
+pydocstyle==6.3.0 \
+ --hash=sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019
+pydot==4.0.1 \
+ --hash=sha256:869c0efadd2708c0be1f916eb669f3d664ca684bc57ffb7ecc08e70d5e93fee6
+pydub==0.25.1 \
+ --hash=sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6
+pyerfa==2.0.1.5 \
+ --hash=sha256:66292d437dcf75925b694977aa06eb697126e7b86553e620371ed3e48b5e0ad0
+pyflakes==3.2.0 \
+ --hash=sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a
+pygithub==2.6.1 \
+ --hash=sha256:6f2fa6d076ccae475f9fc392cc6cdbd54db985d4f69b8833a28397de75ed6ca3
+pygments==2.19.1 \
+ --hash=sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c
+pyjwt==2.10.1 \
+ --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb
+pylint==3.3.6 \
+ --hash=sha256:8b7c2d3e86ae3f94fb27703d521dd0b9b6b378775991f504d7c3a6275aa0a6a6
+pylint-venv==3.0.4 \
+ --hash=sha256:31006a3df398f58f962c9e5620e756b284e8b2bc490594ce5ee5da41920cb32c
+pyls-spyder==0.4.0 \
+ --hash=sha256:1505d975f866a343d0554b6dab41b53717f4b4bc6df450dfd7d48f889fe450b9
+pymongo==4.10.1 \
+ --hash=sha256:45ee87a4e12337353242bc758accc7fb47a2f2d9ecc0382a61e64c8f01e86708
+pympler==1.1 \
+ --hash=sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506
+pynacl==1.5.0 \
+ --hash=sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93
+pynndescent==0.5.13 \
+ --hash=sha256:69aabb8f394bc631b6ac475a1c7f3994c54adf3f51cd63b2730fefba5771b949
+pyodbc==5.2.0 \
+ --hash=sha256:96d3127f28c0dacf18da7ae009cd48eac532d3dcc718a334b86a3c65f6a5ef5c
+pyogrio==0.10.0 \
+ --hash=sha256:02e54bcfb305af75f829044b0045f74de31b77c2d6546f7aaf96822066147848
+pyomo==6.9.2 \
+ --hash=sha256:13ebb2f974f97afa626c2712d4f27e09a1c3d18ca11755676b743504a76e5161
+pypandoc==1.15 \
+ --hash=sha256:4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16
+pyparsing==3.2.3 \
+ --hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf
+pypdf==5.6.0 \
+ --hash=sha256:ca6bf446bfb0a2d8d71d6d6bb860798d864c36a29b3d9ae8d7fc7958c59f88e7
+pyproj==3.7.0 \
+ --hash=sha256:10a8dc6ec61af97c89ff032647d743f8dc023645773da42ef43f7ae1125b3509
+pyproject-hooks==1.2.0 \
+ --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
+pyqt5==5.15.11 \
+ --hash=sha256:bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517
+pyqt5-qt5==5.15.2 \
+ --hash=sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962
+pyqt5-sip==12.17.0 \
+ --hash=sha256:672c209d05661fab8e17607c193bf43991d268a1eefbc2c4551fbf30fd8bb2ca
+pyqtgraph==0.13.7 \
+ --hash=sha256:7754edbefb6c367fa0dfb176e2d0610da3ada20aa7a5318516c74af5fb72bf7a
+pyqtwebengine==5.15.7 \
+ --hash=sha256:bd5e8c426d6f6b352cd15800d64a89b2a4a11e098460b818c7bdcf5e5612e44f
+pyqtwebengine-qt5==5.15.2 \
+ --hash=sha256:24231f19e1595018779977de6722b5c69f3d03f34a5f7574ff21cd1e764ef76d
+pyreadline3==3.5.4 \
+ --hash=sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6
+pyserial==3.5 \
+ --hash=sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0
+pysocks==1.7.1 \
+ --hash=sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5
+pyspnego==0.11.2 \
+ --hash=sha256:74abc1fb51e59360eb5c5c9086e5962174f1072c7a50cf6da0bda9a4bcfdfbd4
+pytest==8.3.5 \
+ --hash=sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820
+python-barcode==0.15.1 \
+ --hash=sha256:057636fba37369c22852410c8535b36adfbeb965ddfd4e5b6924455d692e0886
+python-dateutil==2.8.2 \
+ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
+python-dotenv==1.1.0 \
+ --hash=sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d
+python-json-logger==3.3.0 \
+ --hash=sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7
+python-lsp-black==2.0.0 \
+ --hash=sha256:d5efdee45f5fa9e5241f5d4d396cd46127f45c85817916b1fd92c2986652bf7e
+python-lsp-jsonrpc==1.1.2 \
+ --hash=sha256:7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c
+python-lsp-server==1.12.2 \
+ --hash=sha256:750116459449184ba20811167cdf96f91296ae12f1f65ebd975c5c159388111b
+python-multipart==0.0.20 \
+ --hash=sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104
+python-slugify==8.0.4 \
+ --hash=sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8
+pythonqwt==0.14.5 \
+ --hash=sha256:be5a9d2e1ba22aaa02eb397c5b3b5e4e1d9ed2c08f45554d8b920d8fc3be6dc7
+pytoolconfig==1.3.1 \
+ --hash=sha256:5d8cea8ae1996938ec3eaf44567bbc5ef1bc900742190c439a44a704d6e1b62b
+pytz==2025.2 \
+ --hash=sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00
+pyuca==1.2 \
+ --hash=sha256:abaa12e1bd2c7c68ca8396ff8383bc0654a739cef3ae68fd7af58bf29af0a91e
+pyusb==1.3.1 \
+ --hash=sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430
+pyviz-comms==3.0.4 \
+ --hash=sha256:a40d17db26ec13cf975809633804e712bd24b473e77388c193c44043f85d0b25
+pywavelets==1.8.0 \
+ --hash=sha256:4dbebcfd55ea8a85b7fc8802d411e75337170422abf6e96019d7e46c394e80e5
+pywin32==310 \
+ --hash=sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e
+pywin32-ctypes==0.2.3 \
+ --hash=sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8
+pywinpty==2.0.15 \
+ --hash=sha256:ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408
+pyyaml==6.0.2 \
+ --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563
+pyzmq==26.4.0 \
+ --hash=sha256:23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b
+qdarkstyle==3.2.3 \
+ --hash=sha256:ea980ee426d594909cf1058306832af71ff6cbad6f69237b036d1550635aefbc
+qdldl==0.1.7.post5 \
+ --hash=sha256:cc9be378e7bec67d4c62b7fa27cafb4f77d3e5e059d753c3dce0a5ae1ef5fea0
+qrcode==8.2 \
+ --hash=sha256:16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f
+qstylizer==0.2.4 \
+ --hash=sha256:8f384dfe86f9edb0bb596b93663a51f124f0794b94fd54057cc7cf9cea59fb6f
+qtawesome==1.4.0 \
+ --hash=sha256:a4d689fa071c595aa6184171ce1f0f847677cb8d2db45382c43129f1d72a3d93
+qtconsole==5.6.1 \
+ --hash=sha256:3d22490d9589bace566ad4f3455b61fa2209156f40e87e19e2c3cb64e9264950
+qtpy==2.4.3 \
+ --hash=sha256:72095afe13673e017946cc258b8d5da43314197b741ed2890e563cf384b51aa1
+quantecon==0.8.1 \
+ --hash=sha256:a1f041ed2ed6a9a88e2206998eed85217d3ca903937017cabadfd5a35cbe632e
+quart==0.20.0 \
+ --hash=sha256:003c08f551746710acb757de49d9b768986fd431517d0eb127380b656b98b8f1
+rapidfuzz==3.13.0 \
+ --hash=sha256:9a7c6232be5f809cd39da30ee5d24e6cadd919831e6020ec6c2391f4c3bc9264
+readme-renderer==44.0 \
+ --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151
+redis==5.2.1 \
+ --hash=sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4
+referencing==0.36.2 \
+ --hash=sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0
+regex==2024.11.6 \
+ --hash=sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a
+reportlab==4.4.2 \
+ --hash=sha256:58e11be387457928707c12153b7e41e52533a5da3f587b15ba8f8fd0805c6ee2
+requests==2.32.4 \
+ --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c
+requests-ntlm==1.3.0 \
+ --hash=sha256:4c7534a7d0e482bb0928531d621be4b2c74ace437e88c5a357ceb7452d25a510
+requests-toolbelt==1.0.0 \
+ --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06
+rfc3339-validator==0.1.4 \
+ --hash=sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa
+rfc3986==2.0.0 \
+ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd
+rfc3986-validator==0.1.1 \
+ --hash=sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9
+rich==14.0.0 \
+ --hash=sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0
+rope==1.13.0 \
+ --hash=sha256:b435a0c0971244fdcd8741676a9fae697ae614c20cc36003678a7782f25c0d6c
+rpds-py==0.24.0 \
+ --hash=sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a
+rsa==4.7.2 \
+ --hash=sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2
+rtree==1.4.0 \
+ --hash=sha256:ba83efc7b7563905b1bfdfc14490c4bfb59e92e5e6156bdeb6ec5df5117252f4
+rx==3.2.0 \
+ --hash=sha256:922c5f4edb3aa1beaa47bf61d65d5380011ff6adcd527f26377d05cb73ed8ec8
+scikit-image==0.25.2 \
+ --hash=sha256:64785a8acefee460ec49a354706db0b09d1f325674107d7fa3eadb663fb56d6f
+scikit-learn==1.7.1 \
+ --hash=sha256:ca6d31fb10e04d50bfd2b50d66744729dbb512d4efd0223b864e2fdbfc4cee11
+scipy==1.16.0 \
+ --hash=sha256:79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe
+scramp==1.4.5 \
+ --hash=sha256:50e37c464fc67f37994e35bee4151e3d8f9320e9c204fca83a5d313c121bbbe7
+scs==3.2.7.post2 \
+ --hash=sha256:a2c48cd19e39bf87dae0b20a289fff44930458fc2ca2afa0f899058dc41e5545
+seaborn==0.13.2 \
+ --hash=sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987
+send2trash==1.8.3 \
+ --hash=sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9
+setuptools==80.9.0 \
+ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922
+shapely==2.1.1 \
+ --hash=sha256:ab8d878687b438a2f4c138ed1a80941c6ab0029e0f4c785ecfe114413b498a97
+shellingham==1.5.4 \
+ --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686
+simplejson==3.19.3 \
+ --hash=sha256:3bbcdc438dc1683b35f7a8dc100960c721f922f9ede8127f63bed7dfded4c64c
+simpy==4.1.1 \
+ --hash=sha256:7c5ae380240fd2238671160e4830956f8055830a8317edf5c05e495b3823cd88
+six==1.17.0 \
+ --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274
+skrub==0.6.0 \
+ --hash=sha256:bc7155ca02fb4233abce843716b175619d95b94fb7b9ead4b15fc26453d8f646
+smmap==5.0.2 \
+ --hash=sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e
+sniffio==1.3.1 \
+ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2
+snowballstemmer==2.2.0 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+sortedcontainers==2.4.0 \
+ --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0
+sounddevice==0.5.1 \
+ --hash=sha256:4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1
+soupsieve==2.6 \
+ --hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9
+sphinx==8.1.3 \
+ --hash=sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2
+sphinx-rtd-theme==3.0.2 \
+ --hash=sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13
+sphinxcontrib-applehelp==2.0.0 \
+ --hash=sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5
+sphinxcontrib-devhelp==2.0.0 \
+ --hash=sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2
+sphinxcontrib-htmlhelp==2.1.0 \
+ --hash=sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8
+sphinxcontrib-jquery==4.1 \
+ --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178
+sphinxcontrib-qthelp==2.0.0 \
+ --hash=sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb
+sphinxcontrib-serializinghtml==2.0.0 \
+ --hash=sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331
+spyder==6.0.7 \
+ --hash=sha256:b725569bb8ddc7b0aab73d747d85312dc0456978370cc0f9b1a101c0fe4f076b
+spyder-kernels==3.0.5 \
+ --hash=sha256:9cc808e0ec4426b9ba911128e221fa2234e6c8d6e08526132e90112ff9c2bb7c
+sqlalchemy==2.0.41 \
+ --hash=sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df
+sqlite-bro==0.13.1 \
+ --hash=sha256:c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d
+sqlite-fts4==1.0.3 \
+ --hash=sha256:0359edd8dea6fd73c848989e1e2b1f31a50fe5f9d7272299ff0e8dbaa62d035f
+sqlite-utils==3.38 \
+ --hash=sha256:8a27441015c3b2ef475f555861f7a2592f73bc60d247af9803a11b65fc605bf9
+sqlparse==0.5.3 \
+ --hash=sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca
+squarify==0.4.4 \
+ --hash=sha256:d7597724e29d48aa14fd2f551060d6b09e1f0a67e4cd3ea329fe03b4c9a56f11
+sse-starlette==2.4.1 \
+ --hash=sha256:08b77ea898ab1a13a428b2b6f73cfe6d0e607a7b4e15b9bb23e4a37b087fd39a
+sspilib==0.2.0 \
+ --hash=sha256:c39a698491f43618efca8776a40fb7201d08c415c507f899f0df5ada15abefaa
+stack-data==0.6.3 \
+ --hash=sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695
+starlette==0.46.2 \
+ --hash=sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35
+statsmodels==0.14.4 \
+ --hash=sha256:81030108d27aecc7995cac05aa280cf8c6025f6a6119894eef648997936c2dd0
+streamlit==1.46.1 \
+ --hash=sha256:dffa373230965f87ccc156abaff848d7d731920cf14106f3b99b1ea18076f728
+superqt==0.7.3 \
+ --hash=sha256:8f7d141665b31baa484747f324fc9fc2d14223f2fefc92ffed6ea35c92221304
+sv-ttk==2.6.0 \
+ --hash=sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9
+sympy==1.14.0 \
+ --hash=sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5
+tabulate==0.9.0 \
+ --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
+tblib==3.1.0 \
+ --hash=sha256:670bb4582578134b3d81a84afa1b016128b429f3d48e6cbbaecc9d15675e984e
+tenacity==9.1.2 \
+ --hash=sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138
+termcolor==3.1.0 \
+ --hash=sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa
+terminado==0.18.1 \
+ --hash=sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0
+text-unidecode==1.3 \
+ --hash=sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8
+textdistance==4.6.3 \
+ --hash=sha256:0cb1b2cc8e3339ddc3e0f8c870e49fb49de6ecc42a718917308b3c971f34aa56
+thefuzz==0.22.1 \
+ --hash=sha256:59729b33556850b90e1093c4cf9e618af6f2e4c985df193fdf3c5b5cf02ca481
+threadpoolctl==3.6.0 \
+ --hash=sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb
+three-merge==0.1.1 \
+ --hash=sha256:dd219f4696aa0bbec6099ac3528b4de0450ff9bde862dd8f6d6f52e745f83464
+tifffile==2025.3.30 \
+ --hash=sha256:0ed6eee7b66771db2d1bfc42262a51b01887505d35539daef118f4ff8c0f629c
+tiktoken==0.9.0 \
+ --hash=sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95
+tinycss2==1.4.0 \
+ --hash=sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289
+tokenizers==0.21.1 \
+ --hash=sha256:0f0dcbcc9f6e13e675a66d7a5f2f225a736745ce484c1a4e07476a89ccdad382
+toml==0.10.2 \
+ --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b
+tomli==2.2.1 \
+ --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69
+tomli-w==1.2.0 \
+ --hash=sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90
+tomlkit==0.13.2 \
+ --hash=sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde
+toolz==1.0.0 \
+ --hash=sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236
+tornado==6.5.1 \
+ --hash=sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b
+tqdm==4.67.1 \
+ --hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2
+traitlets==5.14.3 \
+ --hash=sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f
+traittypes==0.2.1 \
+ --hash=sha256:1340af133810b6eee1a2eb2e988f862b0d12b6c2d16f282aaf3207b782134c2e
+trio==0.30.0 \
+ --hash=sha256:3bf4f06b8decf8d3cf00af85f40a89824669e2d033bb32469d34840edcfc22a5
+trove-classifiers==2025.5.9.12 \
+ --hash=sha256:e381c05537adac78881c8fa345fd0e9970159f4e4a04fcc42cfd3129cca640ce
+twine==6.1.0 \
+ --hash=sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384
+typer==0.15.2 \
+ --hash=sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc
+types-python-dateutil==2.9.0.20240316 \
+ --hash=sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b
+types-requests==2.32.0.20250328 \
+ --hash=sha256:72ff80f84b15eb3aa7a8e2625fffb6a93f2ad5a0c20215fc1dcfa61117bcb2a2
+typing-extensions==4.13.2 \
+ --hash=sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c
+typing-inspection==0.4.0 \
+ --hash=sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f
+tzdata==2025.2 \
+ --hash=sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8
+tzlocal==5.3.1 \
+ --hash=sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d
+uc-micro-py==1.0.3 \
+ --hash=sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5
+ujson==5.10.0 \
+ --hash=sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539
+umap-learn==0.5.7 \
+ --hash=sha256:6a7e0be2facfa365a5ed6588447102bdbef32a0ef449535c25c97ea7e680073c
+uncertainties==3.2.2 \
+ --hash=sha256:fd8543355952f4052786ed4150acaf12e23117bd0f5bd03ea07de466bce646e7
+uri-template==1.3.0 \
+ --hash=sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363
+urllib3==2.4.0 \
+ --hash=sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813
+uvicorn==0.34.2 \
+ --hash=sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403
+vega-datasets==0.9.0 \
+ --hash=sha256:3d7c63917be6ca9b154b565f4779a31fedce57b01b5b9d99d8a34a7608062a1d
+waitress==3.0.0 \
+ --hash=sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669
+watchdog==6.0.0 \
+ --hash=sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680
+wcwidth==0.2.13 \
+ --hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859
+webcolors==24.11.1 \
+ --hash=sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9
+webencodings==0.5.1 \
+ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78
+websocket-client==1.8.0 \
+ --hash=sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526
+websockets==14.2 \
+ --hash=sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f
+werkzeug==3.1.3 \
+ --hash=sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e
+whatthepatch==1.0.7 \
+ --hash=sha256:1b6f655fd31091c001c209529dfaabbabdbad438f5de14e3951266ea0fc6e7ed
+wheel==0.45.1 \
+ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
+widgetsnbextension==4.0.14 \
+ --hash=sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575
+wordcloud==1.9.4 \
+ --hash=sha256:8c9a5af2fbcf029a19e827adbee58e86efe7536dca7a42380a8601113a86069b
+wppm==17.2.20250823 \
+ --hash=sha256:0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3
+wrapt==1.16.0 \
+ --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1
+wsproto==1.2.0 \
+ --hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736
+xarray==2025.7.1 \
+ --hash=sha256:e8647b659e53bd350d7c5a91c34dd4122ad6a3ca0bc41399d424a7c0273c7635
+xlsxwriter==3.2.5 \
+ --hash=sha256:4f4824234e1eaf9d95df9a8fe974585ff91d0f5e3d3f12ace5b71e443c1c6abd
+xyzservices==2023.10.1 \
+ --hash=sha256:6a4c38d3a9f89d3e77153eff9414b36a8ee0850c9e8b85796fd1b2a85b8dfd68
+yapf==0.40.1 \
+ --hash=sha256:b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313
+yarl==1.18.3 \
+ --hash=sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c
+yt-dlp==2025.2.19 \
+ --hash=sha256:3ed218eaeece55e9d715afd41abc450dc406ee63bf79355169dfde312d38fdb8
+zict==3.0.0 \
+ --hash=sha256:5796e36bd0e0cc8cf0fbc1ace6a68912611c1dbd74750a3f3026b9b9d6a327ae
+zipp==3.21.0 \
+ --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931
+zstandard==0.23.0 \
+ --hash=sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b
diff --git a/winpython/portable/cycle_2025_04/requir.64-3_13_7_0whlb3_wheels.txt b/winpython/portable/cycle_2025_04/requir.64-3_13_7_0whlb3_wheels.txt
new file mode 100644
index 00000000..557f9563
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/requir.64-3_13_7_0whlb3_wheels.txt
@@ -0,0 +1,978 @@
+absl-py==2.3.0 \
+ --hash=sha256:9824a48b654a306168f63e0d97714665f8490b8d89ec7bf2efc24bf67cf579b3
+adbc-driver-manager==1.6.0 \
+ --hash=sha256:0e8ffb182fafe1e6ae12964a833700daacc55f7abfdc2ada8b5214b18108d87b
+aiofiles==24.1.0 \
+ --hash=sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5
+aiohappyeyeballs==2.6.1 \
+ --hash=sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8
+aiohttp==3.11.18 \
+ --hash=sha256:bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01
+aiosignal==1.3.2 \
+ --hash=sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5
+aiosqlite==0.21.0 \
+ --hash=sha256:2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0
+alabaster==1.0.0 \
+ --hash=sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b
+alembic==1.16.1 \
+ --hash=sha256:0cdd48acada30d93aa1035767d67dff25702f8de74d7c3919f2e8492c8db2e67
+altair==5.5.0 \
+ --hash=sha256:91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c
+annotated-types==0.7.0 \
+ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53
+ansicolors==1.1.8 \
+ --hash=sha256:00d2dde5a675579325902536738dd27e4fac1fd68f773fe36c21044eb559e187
+anthropic==0.64.0 \
+ --hash=sha256:6f5f7d913a6a95eb7f8e1bda4e75f76670e8acd8d4cd965e02e2a256b0429dd1
+anyio==4.9.0 \
+ --hash=sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c
+anywidget==0.9.18 \
+ --hash=sha256:944b82ef1dd17b8ff0fb6d1f199f613caf9111338e6e2857da478f6e73770cb8
+appdirs==1.4.4 \
+ --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128
+argcomplete==3.6.2 \
+ --hash=sha256:65b3133a29ad53fb42c48cf5114752c7ab66c1c38544fdf6460f450c09b42591
+argon2-cffi==25.1.0 \
+ --hash=sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741
+argon2-cffi-bindings==21.2.0 \
+ --hash=sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f
+array-api-compat==1.12.0 \
+ --hash=sha256:a0b4795b6944a9507fde54679f9350e2ad2b1e2acf4a2408a098cdc27f890a8b
+arrow==1.3.0 \
+ --hash=sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80
+asgi-csrf==0.11 \
+ --hash=sha256:03ac140115f39d4295288a9adf74fdc6ae607f6ef44abee8466520458207242b
+asgiref==3.8.1 \
+ --hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47
+asn1crypto==1.5.1 \
+ --hash=sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67
+asteval==1.0.5 \
+ --hash=sha256:082b95312578affc8a6d982f7d92b7ac5de05634985c87e7eedd3188d31149fa
+astroid==3.3.9 \
+ --hash=sha256:d05bfd0acba96a7bd43e222828b7d9bc1e138aaeb0649707908d3702a9831248
+astropy==7.1.0 \
+ --hash=sha256:8e317f34e33a8f5517bc9fc6fbc005f42730d3be7d2820ef41e0468bcb796843
+astropy-iers-data==0.2025.6.9.0.39.3 \
+ --hash=sha256:76855f5572707b8d25f77a0ede2b330b7ef9863bc963e3eda86321e4e32df802
+asttokens==3.0.0 \
+ --hash=sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2
+async-lru==2.0.5 \
+ --hash=sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943
+asyncssh==2.21.0 \
+ --hash=sha256:cf7f3dfa52b2cb4ad31f0d77ff0d0a8fdd850203da84a0e72e62c36fdd4daf4b
+atomicwrites==1.4.0 \
+ --hash=sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197
+attrs==25.3.0 \
+ --hash=sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3
+autopep8==2.0.4 \
+ --hash=sha256:067959ca4a07b24dbd5345efa8325f5f58da4298dab0dde0443d5ed765de80cb
+azure-core==1.34.0 \
+ --hash=sha256:0615d3b756beccdb6624d1c0ae97284f38b78fb59a2a9839bf927c66fbbdddd6
+azure-cosmos==4.9.0 \
+ --hash=sha256:3b60eaa01a16a857d0faf0cec304bac6fa8620a81bc268ce760339032ef617fe
+azure-identity==1.23.0 \
+ --hash=sha256:dbbeb64b8e5eaa81c44c565f264b519ff2de7ff0e02271c49f3cb492762a50b0
+babel==2.17.0 \
+ --hash=sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2
+baresql==1.0.0 \
+ --hash=sha256:a24d17f46beb47c221f328f7e06710e3896c6203a8e1909788d7128f27b86f01
+bcrypt==4.3.0 \
+ --hash=sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b
+beautifulsoup4==4.13.4 \
+ --hash=sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b
+binaryornot==0.4.4 \
+ --hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4
+black==25.1.0 \
+ --hash=sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18
+bleach==6.2.0 \
+ --hash=sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e
+blinker==1.9.0 \
+ --hash=sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc
+bokeh==3.7.3 \
+ --hash=sha256:b0e79dd737f088865212e4fdcb0f3b95d087f0f088bf8ca186a300ab1641e2c7
+branca==0.8.1 \
+ --hash=sha256:d29c5fab31f7c21a92e34bf3f854234e29fecdcf5d2df306b616f20d816be425
+brotli==1.1.0 \
+ --hash=sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b
+build==1.2.2.post1 \
+ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5
+cachetools==5.5.2 \
+ --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a
+certifi==2025.4.26 \
+ --hash=sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3
+cffi==1.17.1 \
+ --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a
+chardet==5.2.0 \
+ --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+charset-normalizer==3.4.2 \
+ --hash=sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980
+clarabel==0.10.0 \
+ --hash=sha256:7871b6f499ad66f71d4e7fb40754c4d986d4316f242beb62ff4f63a69785a50c
+click==8.2.1 \
+ --hash=sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b
+click-default-group==1.2.4 \
+ --hash=sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f
+cloudpickle==3.1.1 \
+ --hash=sha256:c8c5a44295039331ee9dad40ba100a9c7297b6f988e50e87ccdf3765a668350e
+cohere==5.16.1 \
+ --hash=sha256:37e2c1d69b1804071b5e5f5cb44f8b74127e318376e234572d021a1a729c6baa
+colorama==0.4.6 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+coloredlogs==7.3.1 \
+ --hash=sha256:f08ee2a2cef08163ddd24596e48cba2243937abf915d7fb37d62254596b816a9
+colorlog==6.9.0 \
+ --hash=sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff
+comm==0.2.2 \
+ --hash=sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3
+contourpy==1.3.2 \
+ --hash=sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9
+cookiecutter==2.6.0 \
+ --hash=sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d
+cryptography==45.0.5 \
+ --hash=sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63
+cvxpy==1.6.5 \
+ --hash=sha256:51161b0e8b0d83dc07355bab938bd0734dd5531c98dca8d6faaa8b847c651339
+cycler==0.12.1 \
+ --hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30
+cython==3.1.2 \
+ --hash=sha256:8ab1319c77f15b0ae04b3fb03588df3afdec4cf79e90eeea5c961e0ebd8fdf72
+cytoolz==1.0.1 \
+ --hash=sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297
+dask==2025.7.0 \
+ --hash=sha256:073c29c4e99c2400a39a8a67874f35c1d15bf7af9ae3d0c30af3c7c1199f24ae
+datasette==0.65.1 \
+ --hash=sha256:ba7adf717ddcc24a2a8ac57890fffd384a2ebb909b342e4f731ba09eba764305
+datasette-graphql==2.2 \
+ --hash=sha256:cd9f61afdcaab1ce4ff6775296e6ece99305bf05cbfae4c1c938a6c9e60cd485
+deap==1.4.2 \
+ --hash=sha256:1abab976c75b0f18c36e81f968fcc77fac69fc9bedbab8be3323ca376f6fcfa4
+debugpy==1.8.14 \
+ --hash=sha256:684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e
+decorator==5.2.1 \
+ --hash=sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a
+defusedxml==0.7.1 \
+ --hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
+deprecated==1.2.18 \
+ --hash=sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec
+diff-match-patch==20241021 \
+ --hash=sha256:93cea333fb8b2bc0d181b0de5e16df50dd344ce64828226bda07728818936782
+dill==0.4.0 \
+ --hash=sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049
+distributed==2025.7.0 \
+ --hash=sha256:51b74526c2bee409ca968ee5532c79de1c1a1713664f5ccf90bdd81f17cfdc73
+distro==1.9.0 \
+ --hash=sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2
+django==5.2.1 \
+ --hash=sha256:a9b680e84f9a0e71da83e399f1e922e1ab37b2173ced046b541c72e1589a5961
+dnspython==2.7.0 \
+ --hash=sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86
+docstring-to-markdown==0.17 \
+ --hash=sha256:fd7d5094aa83943bf5f9e1a13701866b7c452eac19765380dead666e36d3711c
+docutils==0.21.2 \
+ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
+duckdb==1.3.0 \
+ --hash=sha256:fbdfc1c0b83b90f780ae74038187ee696bb56ab727a289752372d7ec42dda65b
+entrypoints==0.4 \
+ --hash=sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f
+et-xmlfile==2.0.0 \
+ --hash=sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa
+eval-type-backport==0.2.2 \
+ --hash=sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a
+executing==2.2.0 \
+ --hash=sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa
+faker==37.3.0 \
+ --hash=sha256:48c94daa16a432f2d2bc803c7ff602509699fca228d13e97e379cd860a7e216e
+fasta2a==0.2.9 \
+ --hash=sha256:8b855b36f29fde6dcb79ad55be337a8165381b679bec829913009c55581e284e
+fastapi==0.115.12 \
+ --hash=sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d
+fastavro==1.11.1 \
+ --hash=sha256:cde7ed91b52ff21f0f9f157329760ba7251508ca3e9618af3ffdac986d9faaa2
+fastjsonschema==2.21.1 \
+ --hash=sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667
+filelock==3.18.0 \
+ --hash=sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de
+flake8==7.1.1 \
+ --hash=sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213
+flask==3.1.1 \
+ --hash=sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c
+flatbuffers==25.2.10 \
+ --hash=sha256:ebba5f4d5ea615af3f7fd70fc310636fbb2bbd1f566ac0a23d98dd412de50051
+flexcache==0.3 \
+ --hash=sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32
+flexparser==0.4 \
+ --hash=sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846
+flit==3.12.0 \
+ --hash=sha256:2b4e7171dc22881fa6adc2dbf083e5ecc72520be3cd7587d2a803da94d6ef431
+flit-core==3.12.0 \
+ --hash=sha256:e7a0304069ea895172e3c7bb703292e992c5d1555dd1233ab7b5621b5b69e62c
+folium==0.19.5 \
+ --hash=sha256:4333fb3e6f3e9eedb231615d22c6d7df20aea5829554bd6908675865a37803b3
+fonttools==4.58.5 \
+ --hash=sha256:bca61b14031a4b7dc87e14bf6ca34c275f8e4b9f7a37bc2fe746b532a924cf30
+fqdn==1.5.1 \
+ --hash=sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014
+frozenlist==1.7.0 \
+ --hash=sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba
+fsspec==2025.5.1 \
+ --hash=sha256:24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462
+fuzzywuzzy==0.18.0 \
+ --hash=sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993
+geographiclib==2.0 \
+ --hash=sha256:6b7225248e45ff7edcee32becc4e0a1504c606ac5ee163a5656d482e0cd38734
+geopandas==1.0.1 \
+ --hash=sha256:01e147d9420cc374d26f51fc23716ac307f32b49406e4bd8462c07e82ed1d3d6
+geopy==2.4.1 \
+ --hash=sha256:ae8b4bc5c1131820f4d75fce9d4aaaca0c85189b3aa5d64c3dcaf5e3b7b882a7
+gitdb==4.0.12 \
+ --hash=sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf
+gitpython==3.1.44 \
+ --hash=sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110
+google-auth==2.40.3 \
+ --hash=sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca
+google-genai==1.20.0 \
+ --hash=sha256:ccd61d6ebcb14f5c778b817b8010e3955ae4f6ddfeaabf65f42f6d5e3e5a8125
+graphene==3.4.3 \
+ --hash=sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71
+graphql-core==3.2.6 \
+ --hash=sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f
+graphql-relay==3.2.0 \
+ --hash=sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5
+greenlet==3.2.3 \
+ --hash=sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3
+griffe==1.7.3 \
+ --hash=sha256:c6b3ee30c2f0f17f30bcdef5068d6ab7a2a4f1b8bf1a3e74b56fffd21e1c5f75
+groq==0.28.0 \
+ --hash=sha256:c6f86638371c2cba2ca337232e76c8d412e75965ed7e3058d30c9aa5dfe84303
+guidata==3.12.0 \
+ --hash=sha256:8cc05220126dfdd562281de9e761b0c279a4112d699bff55d4b17d95d7bfa1d1
+h11==0.16.0 \
+ --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
+h2==4.2.0 \
+ --hash=sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0
+h5py==3.12.1 \
+ --hash=sha256:52ab036c6c97055b85b2a242cb540ff9590bacfda0c03dd0cf0661b311f522f8
+hatchling==1.27.0 \
+ --hash=sha256:d3a2f3567c4f926ea39849cdf924c7e99e6686c9c8e288ae1037c8fa2a5d937b
+hpack==4.1.0 \
+ --hash=sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496
+html5lib==1.1 \
+ --hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d
+httpcore==1.0.9 \
+ --hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55
+httpie==3.2.4 \
+ --hash=sha256:4bd0435cc4b9bca59501bc65089de96f3e93b393803f32a81951db62050ebf0b
+httpx==0.28.1 \
+ --hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
+httpx-sse==0.4.0 \
+ --hash=sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f
+huggingface-hub==0.34.4 \
+ --hash=sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a
+humanfriendly==10.0 \
+ --hash=sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477
+hupper==1.12.1 \
+ --hash=sha256:e872b959f09d90be5fb615bd2e62de89a0b57efc037bdf9637fb09cdf8552b19
+hypercorn==0.17.3 \
+ --hash=sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547
+hyperframe==6.1.0 \
+ --hash=sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5
+hypothesis==6.135.4 \
+ --hash=sha256:6a3b13ce35d43e14aaf6a6ca4cc411e5342be5d05b77977499d07cf6a61e6e71
+id==1.5.0 \
+ --hash=sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658
+idna==3.10 \
+ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
+imageio==2.37.0 \
+ --hash=sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed
+imagesize==1.4.1 \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b
+importlib-metadata==8.7.0 \
+ --hash=sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd
+inflection==0.5.1 \
+ --hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2
+iniconfig==2.1.0 \
+ --hash=sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760
+intervaltree==3.1.0 \
+ --hash=sha256:902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d
+ipycanvas==0.13.3 \
+ --hash=sha256:d37adb2f45d2fef1c3d33c69a0518055694d87827b2f577f3c426d7712f75daa
+ipykernel==6.29.5 \
+ --hash=sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5
+ipyleaflet==0.20.0 \
+ --hash=sha256:b4c20ddc0b17d68e226cd3367ca2215a4db7e2b14374468c0eeaa54b53e4d173
+ipympl==0.9.7 \
+ --hash=sha256:3698ee7eaa0b047a7603517d7aa1b71b32118a5f51754cab45ec5d994f67208f
+ipython==8.37.0 \
+ --hash=sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2
+ipython-genutils==0.2.0 \
+ --hash=sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8
+ipython-sql==0.5.0 \
+ --hash=sha256:61b46ecffb956f62dbc17b5744cf70c649104c8db9afd821aa39b31f7cbb5d5b
+ipywidgets==8.1.7 \
+ --hash=sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb
+isoduration==20.11.0 \
+ --hash=sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042
+isort==6.0.1 \
+ --hash=sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615
+itsdangerous==2.2.0 \
+ --hash=sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef
+janus==2.0.0 \
+ --hash=sha256:7e6449d34eab04cd016befbd7d8c0d8acaaaab67cb59e076a69149f9031745f9
+jaraco-classes==3.4.0 \
+ --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790
+jaraco-context==6.0.1 \
+ --hash=sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4
+jaraco-functools==4.2.1 \
+ --hash=sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e
+jedi==0.19.2 \
+ --hash=sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9
+jellyfish==1.2.0 \
+ --hash=sha256:c8089e918ddb1abae946e92d053f646a7f686d0d051ef69cdfaa28b37352bbdf
+jinja2==3.1.6 \
+ --hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
+jiter==0.10.0 \
+ --hash=sha256:75f9eb72ecb640619c29bf714e78c9c46c9c4eaafd644bf78577ede459f330d4
+joblib==1.5.1 \
+ --hash=sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a
+json5==0.12.0 \
+ --hash=sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db
+jsonpatch==1.33 \
+ --hash=sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade
+jsonpointer==3.0.0 \
+ --hash=sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942
+jsonschema==4.24.0 \
+ --hash=sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d
+jsonschema-specifications==2025.4.1 \
+ --hash=sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af
+julia==0.6.2 \
+ --hash=sha256:90752f71376fdb9919439d20496c2dab24486dfa4fe8a831d6dd14a1bcbc04d1
+jupyter==1.1.1 \
+ --hash=sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83
+jupyter-bokeh==4.0.5 \
+ --hash=sha256:1110076c14c779071cf492646a1a871aefa8a477261e4721327a666e65df1a2c
+jupyter-client==8.6.3 \
+ --hash=sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f
+jupyter-console==6.6.3 \
+ --hash=sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485
+jupyter-core==5.8.1 \
+ --hash=sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0
+jupyter-events==0.12.0 \
+ --hash=sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb
+jupyter-leaflet==0.20.0 \
+ --hash=sha256:2e27ce83647316424f04845e3a6af35e1ee44c177c318a145646b11f4afe0764
+jupyter-lsp==2.2.5 \
+ --hash=sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da
+jupyter-server==2.16.0 \
+ --hash=sha256:3d8db5be3bc64403b1c65b400a1d7f4647a5ce743f3b20dbdefe8ddb7b55af9e
+jupyter-server-terminals==0.5.3 \
+ --hash=sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa
+jupyterlab==4.4.4 \
+ --hash=sha256:711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd
+jupyterlab-pygments==0.3.0 \
+ --hash=sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780
+jupyterlab-server==2.27.3 \
+ --hash=sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4
+jupyterlab-widgets==3.0.15 \
+ --hash=sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c
+keras==3.11.3 \
+ --hash=sha256:f484f050e05ee400455b05ec8c36ed35edc34de94256b6073f56cfe68f65491f
+keyring==25.6.0 \
+ --hash=sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd
+kiwisolver==1.4.8 \
+ --hash=sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2
+langchain==0.3.27 \
+ --hash=sha256:7b20c4f338826acb148d885b20a73a16e410ede9ee4f19bb02011852d5f98798
+langchain-core==0.3.72 \
+ --hash=sha256:9fa15d390600eb6b6544397a7aa84be9564939b6adf7a2b091179ea30405b240
+langchain-text-splitters==0.3.9 \
+ --hash=sha256:cee0bb816211584ea79cc79927317c358543f40404bcfdd69e69ba3ccde54401
+langsmith==0.4.8 \
+ --hash=sha256:ca2f6024ab9d2cd4d091b2e5b58a5d2cb0c354a0c84fe214145a89ad450abae0
+lazy-loader==0.4 \
+ --hash=sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc
+llvmlite==0.44.0 \
+ --hash=sha256:2fb7c4f2fb86cbae6dca3db9ab203eeea0e22d73b99bc2341cdf9de93612e930
+lmfit==1.3.3 \
+ --hash=sha256:a9e9ec7d0d0ec962cc6c078ad1ec6c8311d3ac0e5f0947a00a91f5509dacc2b2
+locket==1.0.0 \
+ --hash=sha256:b6c819a722f7b6bd955b80781788e4a66a55628b858d347536b7e81325a3a5e3
+logfire-api==3.12.0 \
+ --hash=sha256:fc092c2dcb24c8462ba776f3b0c2183f82e1cd55f86e29b38cf21a048e66a17d
+lxml==6.0.0 \
+ --hash=sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e
+mako==1.3.10 \
+ --hash=sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59
+markdown==3.7 \
+ --hash=sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803
+markdown-it-py==3.0.0 \
+ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1
+markupsafe==3.0.2 \
+ --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f
+matplotlib==3.10.5 \
+ --hash=sha256:07442d2692c9bd1cceaa4afb4bbe5b57b98a7599de4dabfcca92d3eea70f9ebe
+matplotlib-inline==0.1.7 \
+ --hash=sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca
+maturin==1.9.0 \
+ --hash=sha256:fb9796c1893d1e3cd9da9325ef3c63d54a5b0fe6183ddae4954b10c64a1ae5e3
+mccabe==0.7.0 \
+ --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
+mcp==1.9.3 \
+ --hash=sha256:69b0136d1ac9927402ed4cf221d4b8ff875e7132b0b06edd446448766f34f9b9
+mdurl==0.1.2 \
+ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8
+mercantile==1.2.1 \
+ --hash=sha256:30f457a73ee88261aab787b7069d85961a5703bb09dc57a170190bc042cd023f
+mergedeep==1.3.4 \
+ --hash=sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307
+missingno==0.5.2 \
+ --hash=sha256:55782621ce09ba0f0a1d08e5bd6d6fe1946469fb03951fadf7d209911ca5b072
+mistralai==1.9.3 \
+ --hash=sha256:962445e7cebadcbfbcd1daf973e853a832dcf7aba6320468fcf7e2cf5f943aec
+mistune==3.1.3 \
+ --hash=sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9
+mizani==0.11.4 \
+ --hash=sha256:5b6271dc3da2c88694dca2e0e0a7e1879f0e2fb046c789776f54d090a5243735
+ml-dtypes==0.5.1 \
+ --hash=sha256:fd918d4e6a4e0c110e2e05be7a7814d10dc1b95872accbf6512b80a109b71ae1
+mlxtend==0.23.3 \
+ --hash=sha256:f9fec721c4121be87dac00e513456dde5bf56b7427750719c0a291cd58b6538e
+more-itertools==10.7.0 \
+ --hash=sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e
+mpld3==0.5.10 \
+ --hash=sha256:80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1
+mpmath==1.3.0 \
+ --hash=sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c
+msal==1.32.3 \
+ --hash=sha256:b2798db57760b1961b142f027ffb7c8169536bf77316e99a0df5c4aaebb11569
+msal-extensions==1.3.1 \
+ --hash=sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca
+msgpack==1.1.0 \
+ --hash=sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f
+multidict==6.4.4 \
+ --hash=sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373
+mypy==1.16.1 \
+ --hash=sha256:4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee
+mypy-extensions==1.1.0 \
+ --hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505
+namex==0.1.0 \
+ --hash=sha256:e2012a474502f1e2251267062aae3114611f07df4224b6e06334c57b0f2ce87c
+narwhals==2.0.1 \
+ --hash=sha256:837457e36a2ba1710c881fb69e1f79ce44fb81728c92ac378f70892a53af8ddb
+nbclient==0.10.2 \
+ --hash=sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d
+nbconvert==7.16.6 \
+ --hash=sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b
+nbformat==5.10.4 \
+ --hash=sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b
+nest-asyncio==1.6.0 \
+ --hash=sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c
+networkx==3.5 \
+ --hash=sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec
+nh3==0.2.21 \
+ --hash=sha256:bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629
+nltk==3.9.1 \
+ --hash=sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1
+notebook==7.4.2 \
+ --hash=sha256:9ccef602721aaa5530852e3064710b8ae5415c4e2ce26f8896d0433222755259
+notebook-shim==0.2.4 \
+ --hash=sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef
+numba==0.61.2 \
+ --hash=sha256:59321215e2e0ac5fa928a8020ab00b8e57cda8a97384963ac0dfa4d4e6aa54e7
+numpy==2.2.6 \
+ --hash=sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c
+numpydoc==1.8.0 \
+ --hash=sha256:72024c7fd5e17375dec3608a27c03303e8ad00c81292667955c6fea7a3ccf541
+onnxruntime==1.22.1 \
+ --hash=sha256:70980d729145a36a05f74b573435531f55ef9503bcda81fc6c3d6b9306199982
+openai==1.101.0 \
+ --hash=sha256:6539a446cce154f8d9fb42757acdfd3ed9357ab0d34fcac11096c461da87133b
+opencv-python==4.11.0.86 \
+ --hash=sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec
+openpyxl==3.1.5 \
+ --hash=sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2
+opentelemetry-api==1.34.1 \
+ --hash=sha256:b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c
+optree==0.14.1 \
+ --hash=sha256:25ea23fc6d6c0fa7dcf85afcfe10b43ed4fdf0e9d958a3677cd27fcdf0ca17d6
+optuna==4.2.1 \
+ --hash=sha256:6d38199013441d3f70fac27136e05c0188c5f4ec3848db708ac311cbdeb30dbf
+orjson==3.10.18 \
+ --hash=sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52
+osqp==0.6.7.post3 \
+ --hash=sha256:acb219e941f5248da5de3ee9b70e6a5aaddf5f3989dffd1d4c03b0f7b1dfa17b
+outcome==1.3.0.post0 \
+ --hash=sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b
+overrides==7.7.0 \
+ --hash=sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49
+packaging==25.0 \
+ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484
+pandas==2.3.1 \
+ --hash=sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956
+pandocfilters==1.5.1 \
+ --hash=sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc
+papermill==2.6.0 \
+ --hash=sha256:0f09da6ef709f3f14dde77cb1af052d05b14019189869affff374c9e612f2dd5
+parso==0.8.4 \
+ --hash=sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18
+partd==1.4.2 \
+ --hash=sha256:978e4ac767ec4ba5b86c6eaa52e5a2a3bc748a2ca839e8cc798f1cc6ce6efb0f
+pathspec==0.12.1 \
+ --hash=sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08
+patsy==1.0.1 \
+ --hash=sha256:751fb38f9e97e62312e921a1954b81e1bb2bcda4f5eeabaf94db251ee791509c
+pep8==1.7.1 \
+ --hash=sha256:b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee
+pexpect==4.9.0 \
+ --hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523
+pg8000==1.31.2 \
+ --hash=sha256:436c771ede71af4d4c22ba867a30add0bc5c942d7ab27fadbb6934a487ecc8f6
+pickleshare==0.7.5 \
+ --hash=sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56
+pillow==11.3.0 \
+ --hash=sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51
+pip==25.2 \
+ --hash=sha256:6d67a2b4e7f14d8b31b8b52648866fa717f45a1eb70e83002f4331d07e953717
+platformdirs==4.3.7 \
+ --hash=sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94
+plotly==6.2.0 \
+ --hash=sha256:32c444d4c940887219cb80738317040363deefdfee4f354498cc0b6dab8978bd
+plotnine==0.13.6 \
+ --hash=sha256:4acc1af29fa4e91e726b67d49277e8368f62e1c817f01bf14ecd8ca5e83bfaea
+plotpy==2.7.4 \
+ --hash=sha256:8dff5fd388048a8d3b4251329a9fe4027920386e0ebcc3c3642f59c432118c29
+pluggy==1.5.0 \
+ --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669
+ply==3.11 \
+ --hash=sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce
+polars==1.32.2 \
+ --hash=sha256:5e1660a584e89e1d60cd89984feca38a695e491a966581fefe8be99c230ea154
+prettytable==3.16.0 \
+ --hash=sha256:b5eccfabb82222f5aa46b798ff02a8452cf530a352c31bddfa29be41242863aa
+prince==0.16.0 \
+ --hash=sha256:7e21a78d4dd06ca3ec526ee714a50b349f26de3fca6b79664150a951b31688f3
+priority==2.0.0 \
+ --hash=sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa
+prometheus-client==0.21.1 \
+ --hash=sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301
+prompt-toolkit==3.0.51 \
+ --hash=sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07
+propcache==0.3.1 \
+ --hash=sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037
+protobuf==6.30.2 \
+ --hash=sha256:7653c99774f73fe6b9301b87da52af0e69783a2e371e8b599b3e9cb4da4b12b9
+psutil==7.0.0 \
+ --hash=sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553
+psygnal==0.12.0 \
+ --hash=sha256:d779f20c6977ec9d5b9fece23b4b28bbcf0a7773539a4a176b5527aea5da27c7
+ptpython==3.0.30 \
+ --hash=sha256:bec3045f0285ac817c902ef98d6ece31d3e00a4604ef3fdde07d365c78bde23c
+ptyprocess==0.7.0 \
+ --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35
+pure-eval==0.2.3 \
+ --hash=sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0
+pyarrow==21.0.0 \
+ --hash=sha256:186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636
+pyasn1==0.6.1 \
+ --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629
+pyasn1-modules==0.4.1 \
+ --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd
+pybind11==3.0.0 \
+ --hash=sha256:7c5cac504da5a701b5163f0e6a7ba736c713a096a5378383c5b4b064b753f607
+pycodestyle==2.12.0 \
+ --hash=sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4
+pycparser==2.22 \
+ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
+pydantic==2.11.7 \
+ --hash=sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b
+pydantic-ai-slim==0.2.9 \
+ --hash=sha256:d954ff84cb250d7150a7ed694e4f1f92f820205d036ee006d02fce3e62a3bc4e
+pydantic-core==2.33.2 \
+ --hash=sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9
+pydantic-evals==0.2.9 \
+ --hash=sha256:62035ae3a5321e4d892c7372ef91af0f46b675863e827f011d5cb8550dede400
+pydantic-graph==0.2.9 \
+ --hash=sha256:38ad929a0ec205bd7d5875b0b408d4f13448276aa89b6ce2a1143a7552b070ce
+pydantic-settings==2.8.1 \
+ --hash=sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c
+pydeck==0.9.1 \
+ --hash=sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038
+pydocstyle==6.3.0 \
+ --hash=sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019
+pydot==4.0.1 \
+ --hash=sha256:869c0efadd2708c0be1f916eb669f3d664ca684bc57ffb7ecc08e70d5e93fee6
+pydub==0.25.1 \
+ --hash=sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6
+pyerfa==2.0.1.5 \
+ --hash=sha256:66292d437dcf75925b694977aa06eb697126e7b86553e620371ed3e48b5e0ad0
+pyflakes==3.2.0 \
+ --hash=sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a
+pygithub==2.6.1 \
+ --hash=sha256:6f2fa6d076ccae475f9fc392cc6cdbd54db985d4f69b8833a28397de75ed6ca3
+pygments==2.19.1 \
+ --hash=sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c
+pyjwt==2.10.1 \
+ --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb
+pylint==3.3.6 \
+ --hash=sha256:8b7c2d3e86ae3f94fb27703d521dd0b9b6b378775991f504d7c3a6275aa0a6a6
+pylint-venv==3.0.4 \
+ --hash=sha256:31006a3df398f58f962c9e5620e756b284e8b2bc490594ce5ee5da41920cb32c
+pyls-spyder==0.4.0 \
+ --hash=sha256:1505d975f866a343d0554b6dab41b53717f4b4bc6df450dfd7d48f889fe450b9
+pymongo==4.10.1 \
+ --hash=sha256:45ee87a4e12337353242bc758accc7fb47a2f2d9ecc0382a61e64c8f01e86708
+pympler==1.1 \
+ --hash=sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506
+pynacl==1.5.0 \
+ --hash=sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93
+pynndescent==0.5.13 \
+ --hash=sha256:69aabb8f394bc631b6ac475a1c7f3994c54adf3f51cd63b2730fefba5771b949
+pyodbc==5.2.0 \
+ --hash=sha256:96d3127f28c0dacf18da7ae009cd48eac532d3dcc718a334b86a3c65f6a5ef5c
+pyogrio==0.10.0 \
+ --hash=sha256:02e54bcfb305af75f829044b0045f74de31b77c2d6546f7aaf96822066147848
+pyomo==6.9.2 \
+ --hash=sha256:13ebb2f974f97afa626c2712d4f27e09a1c3d18ca11755676b743504a76e5161
+pypandoc==1.15 \
+ --hash=sha256:4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16
+pyparsing==3.2.3 \
+ --hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf
+pypdf==5.6.0 \
+ --hash=sha256:ca6bf446bfb0a2d8d71d6d6bb860798d864c36a29b3d9ae8d7fc7958c59f88e7
+pyproj==3.7.0 \
+ --hash=sha256:10a8dc6ec61af97c89ff032647d743f8dc023645773da42ef43f7ae1125b3509
+pyproject-hooks==1.2.0 \
+ --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
+pyqt5==5.15.11 \
+ --hash=sha256:bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517
+pyqt5-qt5==5.15.2 \
+ --hash=sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962
+pyqt5-sip==12.17.0 \
+ --hash=sha256:672c209d05661fab8e17607c193bf43991d268a1eefbc2c4551fbf30fd8bb2ca
+pyqtgraph==0.13.7 \
+ --hash=sha256:7754edbefb6c367fa0dfb176e2d0610da3ada20aa7a5318516c74af5fb72bf7a
+pyqtwebengine==5.15.7 \
+ --hash=sha256:bd5e8c426d6f6b352cd15800d64a89b2a4a11e098460b818c7bdcf5e5612e44f
+pyqtwebengine-qt5==5.15.2 \
+ --hash=sha256:24231f19e1595018779977de6722b5c69f3d03f34a5f7574ff21cd1e764ef76d
+pyreadline3==3.5.4 \
+ --hash=sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6
+pyserial==3.5 \
+ --hash=sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0
+pysocks==1.7.1 \
+ --hash=sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5
+pyspnego==0.11.2 \
+ --hash=sha256:74abc1fb51e59360eb5c5c9086e5962174f1072c7a50cf6da0bda9a4bcfdfbd4
+pytest==8.3.5 \
+ --hash=sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820
+python-barcode==0.15.1 \
+ --hash=sha256:057636fba37369c22852410c8535b36adfbeb965ddfd4e5b6924455d692e0886
+python-dateutil==2.8.2 \
+ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
+python-dotenv==1.1.0 \
+ --hash=sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d
+python-json-logger==3.3.0 \
+ --hash=sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7
+python-lsp-black==2.0.0 \
+ --hash=sha256:d5efdee45f5fa9e5241f5d4d396cd46127f45c85817916b1fd92c2986652bf7e
+python-lsp-jsonrpc==1.1.2 \
+ --hash=sha256:7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c
+python-lsp-server==1.12.2 \
+ --hash=sha256:750116459449184ba20811167cdf96f91296ae12f1f65ebd975c5c159388111b
+python-multipart==0.0.20 \
+ --hash=sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104
+python-slugify==8.0.4 \
+ --hash=sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8
+pythonqwt==0.14.5 \
+ --hash=sha256:be5a9d2e1ba22aaa02eb397c5b3b5e4e1d9ed2c08f45554d8b920d8fc3be6dc7
+pytoolconfig==1.3.1 \
+ --hash=sha256:5d8cea8ae1996938ec3eaf44567bbc5ef1bc900742190c439a44a704d6e1b62b
+pytz==2025.2 \
+ --hash=sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00
+pyuca==1.2 \
+ --hash=sha256:abaa12e1bd2c7c68ca8396ff8383bc0654a739cef3ae68fd7af58bf29af0a91e
+pyusb==1.3.1 \
+ --hash=sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430
+pywavelets==1.8.0 \
+ --hash=sha256:4dbebcfd55ea8a85b7fc8802d411e75337170422abf6e96019d7e46c394e80e5
+pywin32==310 \
+ --hash=sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e
+pywin32-ctypes==0.2.3 \
+ --hash=sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8
+pywinpty==2.0.15 \
+ --hash=sha256:ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408
+pyyaml==6.0.2 \
+ --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563
+pyzmq==26.4.0 \
+ --hash=sha256:23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b
+qdarkstyle==3.2.3 \
+ --hash=sha256:ea980ee426d594909cf1058306832af71ff6cbad6f69237b036d1550635aefbc
+qdldl==0.1.7.post5 \
+ --hash=sha256:cc9be378e7bec67d4c62b7fa27cafb4f77d3e5e059d753c3dce0a5ae1ef5fea0
+qrcode==8.2 \
+ --hash=sha256:16e64e0716c14960108e85d853062c9e8bba5ca8252c0b4d0231b9df4060ff4f
+qstylizer==0.2.4 \
+ --hash=sha256:8f384dfe86f9edb0bb596b93663a51f124f0794b94fd54057cc7cf9cea59fb6f
+qtawesome==1.4.0 \
+ --hash=sha256:a4d689fa071c595aa6184171ce1f0f847677cb8d2db45382c43129f1d72a3d93
+qtconsole==5.6.1 \
+ --hash=sha256:3d22490d9589bace566ad4f3455b61fa2209156f40e87e19e2c3cb64e9264950
+qtpy==2.4.3 \
+ --hash=sha256:72095afe13673e017946cc258b8d5da43314197b741ed2890e563cf384b51aa1
+quantecon==0.8.1 \
+ --hash=sha256:a1f041ed2ed6a9a88e2206998eed85217d3ca903937017cabadfd5a35cbe632e
+quart==0.20.0 \
+ --hash=sha256:003c08f551746710acb757de49d9b768986fd431517d0eb127380b656b98b8f1
+rapidfuzz==3.13.0 \
+ --hash=sha256:9a7c6232be5f809cd39da30ee5d24e6cadd919831e6020ec6c2391f4c3bc9264
+readme-renderer==44.0 \
+ --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151
+redis==5.2.1 \
+ --hash=sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4
+referencing==0.36.2 \
+ --hash=sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0
+regex==2024.11.6 \
+ --hash=sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a
+reportlab==4.4.2 \
+ --hash=sha256:58e11be387457928707c12153b7e41e52533a5da3f587b15ba8f8fd0805c6ee2
+requests==2.32.4 \
+ --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c
+requests-ntlm==1.3.0 \
+ --hash=sha256:4c7534a7d0e482bb0928531d621be4b2c74ace437e88c5a357ceb7452d25a510
+requests-toolbelt==1.0.0 \
+ --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06
+rfc3339-validator==0.1.4 \
+ --hash=sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa
+rfc3986==2.0.0 \
+ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd
+rfc3986-validator==0.1.1 \
+ --hash=sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9
+rich==14.0.0 \
+ --hash=sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0
+rope==1.13.0 \
+ --hash=sha256:b435a0c0971244fdcd8741676a9fae697ae614c20cc36003678a7782f25c0d6c
+rpds-py==0.24.0 \
+ --hash=sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a
+rsa==4.7.2 \
+ --hash=sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2
+rtree==1.4.0 \
+ --hash=sha256:ba83efc7b7563905b1bfdfc14490c4bfb59e92e5e6156bdeb6ec5df5117252f4
+rx==3.2.0 \
+ --hash=sha256:922c5f4edb3aa1beaa47bf61d65d5380011ff6adcd527f26377d05cb73ed8ec8
+scikit-image==0.25.2 \
+ --hash=sha256:64785a8acefee460ec49a354706db0b09d1f325674107d7fa3eadb663fb56d6f
+scikit-learn==1.7.1 \
+ --hash=sha256:ca6d31fb10e04d50bfd2b50d66744729dbb512d4efd0223b864e2fdbfc4cee11
+scipy==1.16.0 \
+ --hash=sha256:79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe
+scramp==1.4.5 \
+ --hash=sha256:50e37c464fc67f37994e35bee4151e3d8f9320e9c204fca83a5d313c121bbbe7
+scs==3.2.7.post2 \
+ --hash=sha256:a2c48cd19e39bf87dae0b20a289fff44930458fc2ca2afa0f899058dc41e5545
+seaborn==0.13.2 \
+ --hash=sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987
+send2trash==1.8.3 \
+ --hash=sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9
+setuptools==80.9.0 \
+ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922
+shapely==2.1.1 \
+ --hash=sha256:ab8d878687b438a2f4c138ed1a80941c6ab0029e0f4c785ecfe114413b498a97
+shellingham==1.5.4 \
+ --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686
+simplejson==3.19.3 \
+ --hash=sha256:3bbcdc438dc1683b35f7a8dc100960c721f922f9ede8127f63bed7dfded4c64c
+simpy==4.1.1 \
+ --hash=sha256:7c5ae380240fd2238671160e4830956f8055830a8317edf5c05e495b3823cd88
+six==1.17.0 \
+ --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274
+skrub==0.6.0 \
+ --hash=sha256:bc7155ca02fb4233abce843716b175619d95b94fb7b9ead4b15fc26453d8f646
+smmap==5.0.2 \
+ --hash=sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e
+sniffio==1.3.1 \
+ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2
+snowballstemmer==2.2.0 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+sortedcontainers==2.4.0 \
+ --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0
+sounddevice==0.5.1 \
+ --hash=sha256:4313b63f2076552b23ac3e0abd3bcfc0c1c6a696fc356759a13bd113c9df90f1
+soupsieve==2.6 \
+ --hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9
+sphinx==8.1.3 \
+ --hash=sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2
+sphinx-rtd-theme==3.0.2 \
+ --hash=sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13
+sphinxcontrib-applehelp==2.0.0 \
+ --hash=sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5
+sphinxcontrib-devhelp==2.0.0 \
+ --hash=sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2
+sphinxcontrib-htmlhelp==2.1.0 \
+ --hash=sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8
+sphinxcontrib-jquery==4.1 \
+ --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae
+sphinxcontrib-jsmath==1.0.1 \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178
+sphinxcontrib-qthelp==2.0.0 \
+ --hash=sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb
+sphinxcontrib-serializinghtml==2.0.0 \
+ --hash=sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331
+spyder==6.0.7 \
+ --hash=sha256:b725569bb8ddc7b0aab73d747d85312dc0456978370cc0f9b1a101c0fe4f076b
+spyder-kernels==3.0.5 \
+ --hash=sha256:9cc808e0ec4426b9ba911128e221fa2234e6c8d6e08526132e90112ff9c2bb7c
+sqlalchemy==2.0.41 \
+ --hash=sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df
+sqlite-bro==0.13.1 \
+ --hash=sha256:c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d
+sqlite-fts4==1.0.3 \
+ --hash=sha256:0359edd8dea6fd73c848989e1e2b1f31a50fe5f9d7272299ff0e8dbaa62d035f
+sqlite-utils==3.38 \
+ --hash=sha256:8a27441015c3b2ef475f555861f7a2592f73bc60d247af9803a11b65fc605bf9
+sqlparse==0.5.3 \
+ --hash=sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca
+squarify==0.4.4 \
+ --hash=sha256:d7597724e29d48aa14fd2f551060d6b09e1f0a67e4cd3ea329fe03b4c9a56f11
+sse-starlette==2.4.1 \
+ --hash=sha256:08b77ea898ab1a13a428b2b6f73cfe6d0e607a7b4e15b9bb23e4a37b087fd39a
+sspilib==0.2.0 \
+ --hash=sha256:c39a698491f43618efca8776a40fb7201d08c415c507f899f0df5ada15abefaa
+stack-data==0.6.3 \
+ --hash=sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695
+starlette==0.46.2 \
+ --hash=sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35
+statsmodels==0.14.4 \
+ --hash=sha256:81030108d27aecc7995cac05aa280cf8c6025f6a6119894eef648997936c2dd0
+streamlit==1.46.1 \
+ --hash=sha256:dffa373230965f87ccc156abaff848d7d731920cf14106f3b99b1ea18076f728
+superqt==0.7.3 \
+ --hash=sha256:8f7d141665b31baa484747f324fc9fc2d14223f2fefc92ffed6ea35c92221304
+sv-ttk==2.6.0 \
+ --hash=sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9
+sympy==1.14.0 \
+ --hash=sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5
+tabulate==0.9.0 \
+ --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
+tblib==3.1.0 \
+ --hash=sha256:670bb4582578134b3d81a84afa1b016128b429f3d48e6cbbaecc9d15675e984e
+tenacity==9.1.2 \
+ --hash=sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138
+termcolor==3.1.0 \
+ --hash=sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa
+terminado==0.18.1 \
+ --hash=sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0
+text-unidecode==1.3 \
+ --hash=sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8
+textdistance==4.6.3 \
+ --hash=sha256:0cb1b2cc8e3339ddc3e0f8c870e49fb49de6ecc42a718917308b3c971f34aa56
+thefuzz==0.22.1 \
+ --hash=sha256:59729b33556850b90e1093c4cf9e618af6f2e4c985df193fdf3c5b5cf02ca481
+threadpoolctl==3.6.0 \
+ --hash=sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb
+three-merge==0.1.1 \
+ --hash=sha256:dd219f4696aa0bbec6099ac3528b4de0450ff9bde862dd8f6d6f52e745f83464
+tifffile==2025.3.30 \
+ --hash=sha256:0ed6eee7b66771db2d1bfc42262a51b01887505d35539daef118f4ff8c0f629c
+tiktoken==0.9.0 \
+ --hash=sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95
+tinycss2==1.4.0 \
+ --hash=sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289
+tokenizers==0.21.1 \
+ --hash=sha256:0f0dcbcc9f6e13e675a66d7a5f2f225a736745ce484c1a4e07476a89ccdad382
+toml==0.10.2 \
+ --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b
+tomli==2.2.1 \
+ --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69
+tomli-w==1.2.0 \
+ --hash=sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90
+tomlkit==0.13.2 \
+ --hash=sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde
+toolz==1.0.0 \
+ --hash=sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236
+tornado==6.5.1 \
+ --hash=sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b
+tqdm==4.67.1 \
+ --hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2
+traitlets==5.14.3 \
+ --hash=sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f
+traittypes==0.2.1 \
+ --hash=sha256:1340af133810b6eee1a2eb2e988f862b0d12b6c2d16f282aaf3207b782134c2e
+trio==0.30.0 \
+ --hash=sha256:3bf4f06b8decf8d3cf00af85f40a89824669e2d033bb32469d34840edcfc22a5
+trove-classifiers==2025.5.9.12 \
+ --hash=sha256:e381c05537adac78881c8fa345fd0e9970159f4e4a04fcc42cfd3129cca640ce
+twine==6.1.0 \
+ --hash=sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384
+typer==0.15.2 \
+ --hash=sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc
+types-python-dateutil==2.9.0.20240316 \
+ --hash=sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b
+types-requests==2.32.0.20250328 \
+ --hash=sha256:72ff80f84b15eb3aa7a8e2625fffb6a93f2ad5a0c20215fc1dcfa61117bcb2a2
+typing-extensions==4.13.2 \
+ --hash=sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c
+typing-inspection==0.4.0 \
+ --hash=sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f
+tzdata==2025.2 \
+ --hash=sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8
+tzlocal==5.3.1 \
+ --hash=sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d
+ujson==5.10.0 \
+ --hash=sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539
+umap-learn==0.5.7 \
+ --hash=sha256:6a7e0be2facfa365a5ed6588447102bdbef32a0ef449535c25c97ea7e680073c
+uncertainties==3.2.2 \
+ --hash=sha256:fd8543355952f4052786ed4150acaf12e23117bd0f5bd03ea07de466bce646e7
+uri-template==1.3.0 \
+ --hash=sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363
+urllib3==2.4.0 \
+ --hash=sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813
+uvicorn==0.34.2 \
+ --hash=sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403
+vega-datasets==0.9.0 \
+ --hash=sha256:3d7c63917be6ca9b154b565f4779a31fedce57b01b5b9d99d8a34a7608062a1d
+waitress==3.0.0 \
+ --hash=sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669
+watchdog==6.0.0 \
+ --hash=sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680
+wcwidth==0.2.13 \
+ --hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859
+webcolors==24.11.1 \
+ --hash=sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9
+webencodings==0.5.1 \
+ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78
+websocket-client==1.8.0 \
+ --hash=sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526
+websockets==14.2 \
+ --hash=sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f
+werkzeug==3.1.3 \
+ --hash=sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e
+whatthepatch==1.0.7 \
+ --hash=sha256:1b6f655fd31091c001c209529dfaabbabdbad438f5de14e3951266ea0fc6e7ed
+wheel==0.45.1 \
+ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
+widgetsnbextension==4.0.14 \
+ --hash=sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575
+wordcloud==1.9.4 \
+ --hash=sha256:8c9a5af2fbcf029a19e827adbee58e86efe7536dca7a42380a8601113a86069b
+wrapt==1.16.0 \
+ --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1
+wsproto==1.2.0 \
+ --hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736
+xarray==2025.7.1 \
+ --hash=sha256:e8647b659e53bd350d7c5a91c34dd4122ad6a3ca0bc41399d424a7c0273c7635
+xlsxwriter==3.2.5 \
+ --hash=sha256:4f4824234e1eaf9d95df9a8fe974585ff91d0f5e3d3f12ace5b71e443c1c6abd
+xyzservices==2023.10.1 \
+ --hash=sha256:6a4c38d3a9f89d3e77153eff9414b36a8ee0850c9e8b85796fd1b2a85b8dfd68
+yapf==0.40.1 \
+ --hash=sha256:b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313
+yarl==1.18.3 \
+ --hash=sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c
+yt-dlp==2025.2.19 \
+ --hash=sha256:3ed218eaeece55e9d715afd41abc450dc406ee63bf79355169dfde312d38fdb8
+zict==3.0.0 \
+ --hash=sha256:5796e36bd0e0cc8cf0fbc1ace6a68912611c1dbd74750a3f3026b9b9d6a327ae
+zipp==3.21.0 \
+ --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931
+zstandard==0.23.0 \
+ --hash=sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b
diff --git a/winpython/portable/cycle_2025_04/requir.64-3_14_0_1dotb3.txt b/winpython/portable/cycle_2025_04/requir.64-3_14_0_1dotb3.txt
new file mode 100644
index 00000000..8f1d0eee
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/requir.64-3_14_0_1dotb3.txt
@@ -0,0 +1,18 @@
+build==1.2.2.post1 \
+ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5
+colorama==0.4.6 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+packaging==25.0 \
+ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484
+pyproject-hooks==1.2.0 \
+ --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
+setuptools==80.9.0 \
+ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922
+sqlite-bro==0.13.1 \
+ --hash=sha256:c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d
+sv-ttk==2.6.0 \
+ --hash=sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9
+wheel==0.45.1 \
+ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
+wppm==17.2.20250823 \
+ --hash=sha256:0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3
diff --git a/winpython/portable/cycle_2025_04/requir.64-3_14_0_1freeb3.txt b/winpython/portable/cycle_2025_04/requir.64-3_14_0_1freeb3.txt
new file mode 100644
index 00000000..8f1d0eee
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/requir.64-3_14_0_1freeb3.txt
@@ -0,0 +1,18 @@
+build==1.2.2.post1 \
+ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5
+colorama==0.4.6 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+packaging==25.0 \
+ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484
+pyproject-hooks==1.2.0 \
+ --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
+setuptools==80.9.0 \
+ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922
+sqlite-bro==0.13.1 \
+ --hash=sha256:c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d
+sv-ttk==2.6.0 \
+ --hash=sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9
+wheel==0.45.1 \
+ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
+wppm==17.2.20250823 \
+ --hash=sha256:0945411b12eaf6da134a9d8662a4afb2b25e129dd34fc2f6ef76ee62d61411c3
diff --git a/winpython/portable/cycle_2025_04/requir.wppmbuild.txt b/winpython/portable/cycle_2025_04/requir.wppmbuild.txt
new file mode 100644
index 00000000..f1c6adf3
--- /dev/null
+++ b/winpython/portable/cycle_2025_04/requir.wppmbuild.txt
@@ -0,0 +1,68 @@
+build==1.2.2.post1 \
+ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5
+certifi==2025.4.26 \
+ --hash=sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3
+charset-normalizer==3.4.2 \
+ --hash=sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980
+colorama==0.4.6 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+docutils==0.21.2 \
+ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
+flit==3.12.0 \
+ --hash=sha256:2b4e7171dc22881fa6adc2dbf083e5ecc72520be3cd7587d2a803da94d6ef431
+flit-core==3.12.0 \
+ --hash=sha256:e7a0304069ea895172e3c7bb703292e992c5d1555dd1233ab7b5621b5b69e62c
+id==1.5.0 \
+ --hash=sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658
+idna==3.10 \
+ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
+jaraco-classes==3.4.0 \
+ --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790
+jaraco-context==6.0.1 \
+ --hash=sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4
+jaraco-functools==4.1.0 \
+ --hash=sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649
+keyring==25.6.0 \
+ --hash=sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd
+markdown-it-py==3.0.0 \
+ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1
+mdurl==0.1.2 \
+ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8
+more-itertools==10.7.0 \
+ --hash=sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e
+nh3==0.2.21 \
+ --hash=sha256:bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629
+packaging==25.0 \
+ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484
+pygments==2.19.1 \
+ --hash=sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c
+pyproject-hooks==1.2.0 \
+ --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
+pywin32-ctypes==0.2.3 \
+ --hash=sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8
+readme-renderer==44.0 \
+ --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151
+requests==2.32.3 \
+ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
+requests-toolbelt==1.0.0 \
+ --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06
+rfc3986==2.0.0 \
+ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd
+rich==14.0.0 \
+ --hash=sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0
+setuptools==80.9.0 \
+ --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922
+sqlite-bro==0.13.1 \
+ --hash=sha256:c26033b0af133049ca578b5fd30b2372f002e7ff934b39774aa4d2da7638c23d
+sv-ttk==2.6.0 \
+ --hash=sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9
+tomli-w==1.2.0 \
+ --hash=sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90
+twine==6.1.0 \
+ --hash=sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384
+urllib3==2.4.0 \
+ --hash=sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813
+wheel==0.45.1 \
+ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
+wppm==17.2.20250802b2 \
+ --hash=sha256:ed916dcefbc2d597a77cc74d459e8661c59584a690a7d4063d60976fb4d1499f
diff --git a/winpython/portable/launchers_building/build_my_launchers.bat b/winpython/portable/launchers_building/build_my_launchers.bat
new file mode 100644
index 00000000..2585eb5c
--- /dev/null
+++ b/winpython/portable/launchers_building/build_my_launchers.bat
@@ -0,0 +1,37 @@
+rem build launchers in WINDOWS and CONSOLE version
+rem tweaked from @datalab-winpython provided code in \launchers_src
+rem @datalab-winpython licence is in \launchers_src\LICENCE
+@echo off
+
+set VCVARS_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
+
+rem pick the right ones and rename them in launchers_final
+set do_launcher=%~dp0launchers_src\build_one_launcher.bat
+set do_launcher_original=%~dp0launchers_src_original\build_one_launcher.bat
+
+
+echo displace this pause if you want to re-build more
+pause
+rem exit
+
+
+:: WINDOWS launchers with Drag & Drop
+call %do_launcher% "python.ico" "winidle.bat" "IDLE (Python GUI)" WINDOWS proposed
+call %do_launcher% "spyder.ico" "winspyder.bat" "Spyder" WINDOWS proposed
+
+:: CONSOLE launchers with Drag & Drop
+call %do_launcher% "jupyter.ico" "winipython_notebook.bat" "Jupyter Notebook" CONSOLE proposed
+call %do_launcher% "jupyter.ico" "winjupyter_lab.bat" "Jupyter Lab" CONSOLE proposed
+call %do_launcher% "winpython.ico" "wpcp.bat" "WinPython Control Panel" CONSOLE proposed
+
+:: WINDOWS launchers with no Drag & Drop
+call %do_launcher_original% "powershell.ico" "cmd_ps.bat" "WinPython Powershell Prompt" WINDOWS proposed
+call %do_launcher_original% "spyder_reset.ico" "spyder_reset.bat" "Spyder reset" WINDOWS proposed
+call %do_launcher_original% "code.ico" "winvscode.bat" "VS Code" WINDOWS proposed
+
+:: CONSOLE launchers with no Drag & Drop
+call %do_launcher_original% "cmd.ico" "cmd.bat" "WinPython Command Prompt" CONSOLE proposed
+call %do_launcher_original% "python.ico" "winpython.bat" "WinPython Interpreter" CONSOLE proposed
+
+pause
+
diff --git a/portable/icons/cmd.ico b/winpython/portable/launchers_building/icons/cmd.ico
similarity index 100%
rename from portable/icons/cmd.ico
rename to winpython/portable/launchers_building/icons/cmd.ico
diff --git a/portable/icons/code.ico b/winpython/portable/launchers_building/icons/code.ico
similarity index 100%
rename from portable/icons/code.ico
rename to winpython/portable/launchers_building/icons/code.ico
diff --git a/portable/icons/ijulia.ico b/winpython/portable/launchers_building/icons/ijulia.ico
similarity index 100%
rename from portable/icons/ijulia.ico
rename to winpython/portable/launchers_building/icons/ijulia.ico
diff --git a/portable/icons/install.ico b/winpython/portable/launchers_building/icons/install.ico
similarity index 100%
rename from portable/icons/install.ico
rename to winpython/portable/launchers_building/icons/install.ico
diff --git a/portable/icons/ipython.ico b/winpython/portable/launchers_building/icons/ipython.ico
similarity index 100%
rename from portable/icons/ipython.ico
rename to winpython/portable/launchers_building/icons/ipython.ico
diff --git a/portable/icons/julia.ico b/winpython/portable/launchers_building/icons/julia.ico
similarity index 100%
rename from portable/icons/julia.ico
rename to winpython/portable/launchers_building/icons/julia.ico
diff --git a/portable/icons/jupyter.ico b/winpython/portable/launchers_building/icons/jupyter.ico
similarity index 100%
rename from portable/icons/jupyter.ico
rename to winpython/portable/launchers_building/icons/jupyter.ico
diff --git a/winpython/portable/launchers_building/icons/powershell.ico b/winpython/portable/launchers_building/icons/powershell.ico
new file mode 100644
index 00000000..ad1e1489
Binary files /dev/null and b/winpython/portable/launchers_building/icons/powershell.ico differ
diff --git a/portable/icons/python.ico b/winpython/portable/launchers_building/icons/python.ico
similarity index 100%
rename from portable/icons/python.ico
rename to winpython/portable/launchers_building/icons/python.ico
diff --git a/winpython/portable/launchers_building/icons/spyder.ico b/winpython/portable/launchers_building/icons/spyder.ico
new file mode 100644
index 00000000..8b051eab
Binary files /dev/null and b/winpython/portable/launchers_building/icons/spyder.ico differ
diff --git a/winpython/portable/launchers_building/icons/spyder_reset.ico b/winpython/portable/launchers_building/icons/spyder_reset.ico
new file mode 100644
index 00000000..61edabdc
Binary files /dev/null and b/winpython/portable/launchers_building/icons/spyder_reset.ico differ
diff --git a/portable/icons/terminal.ico b/winpython/portable/launchers_building/icons/terminal.ico
similarity index 100%
rename from portable/icons/terminal.ico
rename to winpython/portable/launchers_building/icons/terminal.ico
diff --git a/portable/icons/uninstall.ico b/winpython/portable/launchers_building/icons/uninstall.ico
similarity index 100%
rename from portable/icons/uninstall.ico
rename to winpython/portable/launchers_building/icons/uninstall.ico
diff --git a/winpython/portable/launchers_building/icons/winpython.ico b/winpython/portable/launchers_building/icons/winpython.ico
new file mode 100644
index 00000000..3b8d6a69
Binary files /dev/null and b/winpython/portable/launchers_building/icons/winpython.ico differ
diff --git a/portable/images/banner.bmp b/winpython/portable/launchers_building/images/banner.bmp
similarity index 100%
rename from portable/images/banner.bmp
rename to winpython/portable/launchers_building/images/banner.bmp
diff --git a/portable/images/banner.pdn b/winpython/portable/launchers_building/images/banner.pdn
similarity index 100%
rename from portable/images/banner.pdn
rename to winpython/portable/launchers_building/images/banner.pdn
diff --git a/portable/images/installer_logo.bmp b/winpython/portable/launchers_building/images/installer_logo.bmp
similarity index 100%
rename from portable/images/installer_logo.bmp
rename to winpython/portable/launchers_building/images/installer_logo.bmp
diff --git a/portable/images/splash.bmp b/winpython/portable/launchers_building/images/splash.bmp
similarity index 100%
rename from portable/images/splash.bmp
rename to winpython/portable/launchers_building/images/splash.bmp
diff --git a/portable/images/splash.pdn b/winpython/portable/launchers_building/images/splash.pdn
similarity index 100%
rename from portable/images/splash.pdn
rename to winpython/portable/launchers_building/images/splash.pdn
diff --git a/portable/images/win.bmp b/winpython/portable/launchers_building/images/win.bmp
similarity index 100%
rename from portable/images/win.bmp
rename to winpython/portable/launchers_building/images/win.bmp
diff --git a/portable/images/win.pdn b/winpython/portable/launchers_building/images/win.pdn
similarity index 100%
rename from portable/images/win.pdn
rename to winpython/portable/launchers_building/images/win.pdn
diff --git a/portable/images/winpython_title.svg b/winpython/portable/launchers_building/images/winpython_title.svg
similarity index 100%
rename from portable/images/winpython_title.svg
rename to winpython/portable/launchers_building/images/winpython_title.svg
diff --git a/portable/images/winpython_title_portrait.svg b/winpython/portable/launchers_building/images/winpython_title_portrait.svg
similarity index 100%
rename from portable/images/winpython_title_portrait.svg
rename to winpython/portable/launchers_building/images/winpython_title_portrait.svg
diff --git a/winpython/portable/launchers_building/launchers_final_original/IDLE (Python GUI).exe b/winpython/portable/launchers_building/launchers_final_original/IDLE (Python GUI).exe
new file mode 100644
index 00000000..c1e0c9dc
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/IDLE (Python GUI).exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/Jupyter Lab.exe b/winpython/portable/launchers_building/launchers_final_original/Jupyter Lab.exe
new file mode 100644
index 00000000..98bb8bde
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/Jupyter Lab.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/Jupyter Notebook.exe b/winpython/portable/launchers_building/launchers_final_original/Jupyter Notebook.exe
new file mode 100644
index 00000000..5d59af59
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/Jupyter Notebook.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/Spyder reset.exe b/winpython/portable/launchers_building/launchers_final_original/Spyder reset.exe
new file mode 100644
index 00000000..21250f98
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/Spyder reset.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/Spyder.exe b/winpython/portable/launchers_building/launchers_final_original/Spyder.exe
new file mode 100644
index 00000000..43874aa7
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/Spyder.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/VS Code.exe b/winpython/portable/launchers_building/launchers_final_original/VS Code.exe
new file mode 100644
index 00000000..225decb4
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/VS Code.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/WinPython Command Prompt.exe b/winpython/portable/launchers_building/launchers_final_original/WinPython Command Prompt.exe
new file mode 100644
index 00000000..e4e824c5
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/WinPython Command Prompt.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/WinPython Control Panel.exe b/winpython/portable/launchers_building/launchers_final_original/WinPython Control Panel.exe
new file mode 100644
index 00000000..5795bf9c
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/WinPython Control Panel.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/WinPython Interpreter.exe b/winpython/portable/launchers_building/launchers_final_original/WinPython Interpreter.exe
new file mode 100644
index 00000000..dfa43135
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/WinPython Interpreter.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_original/WinPython Powershell Prompt.exe b/winpython/portable/launchers_building/launchers_final_original/WinPython Powershell Prompt.exe
new file mode 100644
index 00000000..d4512f32
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_original/WinPython Powershell Prompt.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI).exe b/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI).exe
new file mode 100644
index 00000000..65523199
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI).exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI)_2025-05-09_not_ok.exe b/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI)_2025-05-09_not_ok.exe
new file mode 100644
index 00000000..01eed2ce
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI)_2025-05-09_not_ok.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI)_20250401.exe b/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI)_20250401.exe
new file mode 100644
index 00000000..c1e0c9dc
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/IDLE (Python GUI)_20250401.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/Jupyter Lab.exe b/winpython/portable/launchers_building/launchers_final_proposed/Jupyter Lab.exe
new file mode 100644
index 00000000..93003fcb
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/Jupyter Lab.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/Jupyter Notebook.exe b/winpython/portable/launchers_building/launchers_final_proposed/Jupyter Notebook.exe
new file mode 100644
index 00000000..28fdbea3
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/Jupyter Notebook.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/Spyder reset.exe b/winpython/portable/launchers_building/launchers_final_proposed/Spyder reset.exe
new file mode 100644
index 00000000..0baf4ab3
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/Spyder reset.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/Spyder.exe b/winpython/portable/launchers_building/launchers_final_proposed/Spyder.exe
new file mode 100644
index 00000000..93b1a050
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/Spyder.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/Spyder_2025-05-08_no_drag_and_drop.exe b/winpython/portable/launchers_building/launchers_final_proposed/Spyder_2025-05-08_no_drag_and_drop.exe
new file mode 100644
index 00000000..f3729201
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/Spyder_2025-05-08_no_drag_and_drop.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/VS Code.exe b/winpython/portable/launchers_building/launchers_final_proposed/VS Code.exe
new file mode 100644
index 00000000..731f5f52
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/VS Code.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/WinPython Command Prompt.exe b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Command Prompt.exe
new file mode 100644
index 00000000..6f1b6bd6
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Command Prompt.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/WinPython Control Panel.exe b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Control Panel.exe
new file mode 100644
index 00000000..72a57a67
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Control Panel.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/WinPython Control Panel_2025-05-09.exe b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Control Panel_2025-05-09.exe
new file mode 100644
index 00000000..664ff576
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Control Panel_2025-05-09.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/WinPython Interpreter.exe b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Interpreter.exe
new file mode 100644
index 00000000..e0cdbe77
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Interpreter.exe differ
diff --git a/winpython/portable/launchers_building/launchers_final_proposed/WinPython Powershell Prompt.exe b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Powershell Prompt.exe
new file mode 100644
index 00000000..c6bda2eb
Binary files /dev/null and b/winpython/portable/launchers_building/launchers_final_proposed/WinPython Powershell Prompt.exe differ
diff --git a/portable/license.txt b/winpython/portable/launchers_building/launchers_final_proposed/license.txt
similarity index 97%
rename from portable/license.txt
rename to winpython/portable/launchers_building/launchers_final_proposed/license.txt
index 75f3c134..da461f3b 100644
--- a/portable/license.txt
+++ b/winpython/portable/launchers_building/launchers_final_proposed/license.txt
@@ -1,37 +1,37 @@
-Note
-----
-
-WinPython components are distributed as they were received from
-their copyright holder, under their own copyright and/or license,
-and without any linking with each other.
-
-WinPython software collection (i.e. the collection of software,
-libraries and documents) is licensed under the terms of the
-following license agreement.
-
-
-WinPython License Agreement (MIT License)
------------------------------------------
-
-Copyright (c) 2012 Pierre Raybaut, 2016+ WinPython team
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+Note
+----
+
+WinPython components are distributed as they were received from
+their copyright holder, under their own copyright and/or license,
+and without any linking with each other.
+
+WinPython software collection (i.e. the collection of software,
+libraries and documents) is licensed under the terms of the
+following license agreement.
+
+
+WinPython License Agreement (MIT License)
+-----------------------------------------
+
+Copyright (c) 2012 Pierre Raybaut, 2016+ WinPython team
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/winpython/portable/launchers_building/launchers_src/LICENSE b/winpython/portable/launchers_building/launchers_src/LICENSE
new file mode 100644
index 00000000..b3fb976c
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src/LICENSE
@@ -0,0 +1,63 @@
+DataLab-WinPython license terms
+===============================
+
+DataLab-WinPython is a Python distribution for Windows:
+- Based on WinPython, a portable distribution of Python for Windows (see section I. below).
+- Including DataLab, an open-source platform for signal and image processing (see section II. below).
+
+I. - WinPython License Agreement (MIT License)
+----------------------------------------------
+
+Copyright (c) 2012 Pierre Raybaut, 2016+ WinPython team
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+II. - DataLab License Agreement (BSD 3-Clause License)
+------------------------------------------------------
+
+Copyright (c) 2023, DataLab Platform Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/winpython/portable/launchers_building/launchers_src/build_one_launcher.bat b/winpython/portable/launchers_building/launchers_src/build_one_launcher.bat
new file mode 100644
index 00000000..c48374c4
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src/build_one_launcher.bat
@@ -0,0 +1,108 @@
+@echo on
+set icon_name=%1
+set LAUNCH_TARGET=%2
+set launcher_name=%3
+set subsystem=%4
+set destination=%5
+
+set icon_name=%icon_name:"=%
+set LAUNCH_TARGET=%LAUNCH_TARGET:"=%
+set launcher_name=%launcher_name:"=%
+set subsystem=%subsystem:"=%
+
+set ROOT_PATH=%~dp0..\
+set SCRIPT_PATH=%~dp0
+set TEMPO_PATH=%ROOT_PATH%launchers_temp
+set OUTPUT_DIR=%ROOT_PATH%launchers_%destination%
+
+set "ICON_FILE=%ROOT_PATH%icons\%icon_name%"
+set LAUNCHER_EXE=%OUTPUT_DIR%\%launcher_name%.exe
+
+
+:: Paths to template WINDOWS or CONSOLE
+set SOURCE_FILE=%SCRIPT_PATH%launcher_template_%subsystem%.cpp
+echo SOURCE_FILE=%SOURCE_FILE%
+
+set "RESOURCE_FILE=%TEMPO_PATH%\%icon_name%.rc"
+set "RESOURCE_OBJ=%TEMPO_PATH%\%icon_name%.res"
+
+
+:: create pDirectory if needed
+if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%"
+if not exist "%TEMPO_PATH%" mkdir "%TEMPO_PATH%"
+
+cd/d %TEMPO_PATH%
+
+:: Check if MSVC environment is already initialized
+if not defined VSINSTALLDIR (
+ echo Initializing MSVC environment...
+ call %VCVARS_PATH%
+ if errorlevel 1 (
+ echo [ERROR] Failed to initialize MSVC environment.
+ exit /b 1
+ )
+)
+
+@echo on
+
+:: Walk through .bat files in the current directory
+ echo Processing %icon_name%..
+ :: Stonebig: Remove previous .exe file
+ echo launcher_exe_action del /q "%LAUNCHER_EXE%"
+ if exist "%LAUNCHER_EXE%" (
+ move "%LAUNCHER_EXE%" "%LAUNCHER_EXE%.old.exe"
+ del /q "%LAUNCHER_EXE%.old.exe"
+ )
+ :: Stonebig: Remove intermediate .res and.rc file
+ if exist "%RESOURCE_OBJ%" (
+ move "%RESOURCE_OBJ%" "%RESOURCE_OBJ%.old.exe"
+ del /q "%RESOURCE_OBJ%.old.exe"
+ )
+ if exist "%RESOURCE_FILE%" (
+ move "%RESOURCE_FILE%" "%RESOURCE_FILE%.old.exe"
+ del /q "%RESOURCE_FILE%.old.exe"
+ )
+ :: Remove intermediate .obj file
+ del /q "launcher_template_%subsystem%.obj"
+
+ :: Check if the icon exists
+ if exist "%ICON_FILE%" (
+ echo Icon found: "%ICON_FILE%"
+ ) else (
+ echo No icon found for "%ICON_FILE%" stoping
+ pause
+ exit
+ )
+
+
+ :: Create resource file
+ echo Creating resource file...
+ > "%RESOURCE_FILE%" echo IDI_ICON1 ICON "%ICON_FILE%"
+ :: Compile resource
+ echo Compiling resource...
+ rc /fo "%RESOURCE_OBJ%" "%RESOURCE_FILE%"
+
+ :: Compile the launcher executable
+ echo Compiling launcher executable...
+ cl /EHsc /O2 /DUNICODE /W4 "%SOURCE_FILE%" "%RESOURCE_OBJ%" ^
+ /Fe"%LAUNCHER_EXE%%" ^
+ /DLAUNCH_TARGET=\"%LAUNCH_TARGET%\" ^
+ User32.lib ^
+ /link /SUBSYSTEM:%subsystem%
+
+
+ if errorlevel 1 (
+ echo [ERROR] Failed to build launcher for %LAUNCH_TARGET%
+ exit /b 1
+ )
+
+ if exist "%LAUNCHER_EXE%" (
+ echo [SUCCESS] Launcher created: "%LAUNCHER_EXE%""
+ ) else (
+ echo [ERROR] Failed to build launcher "%LAUNCHER_EXE%" from "%icon_name%" to call "%LAUNCH_TARGET%"
+ exit /b 1
+ )
+
+echo All launchers processed.
+rem exit /b 0
+
diff --git a/winpython/portable/launchers_building/launchers_src/launcher_template_CONSOLE.cpp b/winpython/portable/launchers_building/launchers_src/launcher_template_CONSOLE.cpp
new file mode 100644
index 00000000..1008d7f0
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src/launcher_template_CONSOLE.cpp
@@ -0,0 +1,100 @@
+/*
+DataLab-WinPython launcher script
+---------------------------------
+
+Licensed under the terms of the BSD 3-Clause
+(see ./LICENSE for details)
+
+*/
+
+#include
+#include
+
+int main() {
+ // Get the path to the current executable
+ wchar_t exePath[MAX_PATH];
+ GetModuleFileNameW(NULL, exePath, MAX_PATH);
+
+ // Determine the directory of the executable
+ std::wstring exeDir = exePath;
+ exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/"));
+
+ // Get command line string and extract arguments
+ LPWSTR commandLine = GetCommandLineW();
+ std::wstring args;
+ // If executable path is double quoted, skip the entire quoted section
+ if (commandLine[0] == L'"') {
+ LPWSTR closingQuote = wcschr(commandLine + 1, L'"');
+ if (closingQuote) {
+ args = closingQuote + 1;
+ }
+ // For non-quoted path, skip to character after first space if it exists
+ } else {
+ LPWSTR spacePos = wcschr(commandLine, L' ');
+ if (spacePos) {
+ args = spacePos + 1;
+ }
+ }
+ // Strip leading whitespace
+ size_t args_start = args.find_first_not_of(L' ');
+ args = (args_start != std::wstring::npos) ? args.substr(args_start) : L"";
+
+ // Define the path to the "scripts" directory
+ std::wstring scriptsDir = exeDir + L"\\scripts";
+
+ // Check if the "scripts" directory exists
+ DWORD attributes = GetFileAttributesW(scriptsDir.c_str());
+ if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ MessageBoxW(NULL, L"The 'scripts' directory does not exist. Please ensure it is in the same folder as the launcher.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Set the working directory to the "scripts" folder
+ if (!SetCurrentDirectoryW(scriptsDir.c_str())) {
+ MessageBoxW(NULL, L"Failed to set the working directory to 'scripts'.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Define the command to run and append arguments if present
+ std::wstring target;
+ if (!args.empty()) {
+ target = L"cmd.exe /c \"\"" LAUNCH_TARGET L"\" " + args + L"\"";
+ } else {
+ target = L"cmd.exe /c \"" LAUNCH_TARGET L"\"";
+ }
+
+ // Configure the process startup info
+ STARTUPINFO si = { sizeof(si) };
+ si.dwFlags = STARTF_USESHOWWINDOW; // Prevent the window from appearing
+ si.wShowWindow = SW_HIDE; // Hide the command window
+
+ PROCESS_INFORMATION pi = {};
+
+ // Start the process without CREATE_NO_WINDOW flag to show the command window
+ if (!CreateProcessW(
+ NULL, // Application name (NULL because we pass the command in the command line)
+ &target[0], // Command line
+ NULL, // Process security attributes
+ NULL, // Thread security attributes
+ FALSE, // Inherit handles
+ 0, // No special flags
+ NULL, // Environment block (NULL to inherit parent)
+ NULL, // Current directory (NULL to use the parent process's current directory)
+ &si, // Startup info
+ &pi // Process information
+ )) {
+ MessageBoxW(NULL, L"Failed to launch the script.", L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Wait for the script to finish
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // Cleanup
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return 0;
+}
diff --git a/winpython/portable/launchers_building/launchers_src/launcher_template_WINDOWS.cpp b/winpython/portable/launchers_building/launchers_src/launcher_template_WINDOWS.cpp
new file mode 100644
index 00000000..6b10a89a
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src/launcher_template_WINDOWS.cpp
@@ -0,0 +1,100 @@
+/*
+DataLab-WinPython launcher script
+---------------------------------
+
+Licensed under the terms of the BSD 3-Clause
+(see ./LICENSE for details)
+
+*/
+
+#include
+#include
+
+int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/) {
+ // Get the path to the current executable
+ wchar_t exePath[MAX_PATH];
+ GetModuleFileNameW(NULL, exePath, MAX_PATH);
+
+ // Determine the directory of the executable
+ std::wstring exeDir = exePath;
+ exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/"));
+
+ // Get command line string and extract arguments
+ LPWSTR commandLine = GetCommandLineW();
+ std::wstring args;
+ // If executable path is double quoted, skip the entire quoted section
+ if (commandLine[0] == L'"') {
+ LPWSTR closingQuote = wcschr(commandLine + 1, L'"');
+ if (closingQuote) {
+ args = closingQuote + 1;
+ }
+ // For non-quoted path, skip to character after first space if it exists
+ } else {
+ LPWSTR spacePos = wcschr(commandLine, L' ');
+ if (spacePos) {
+ args = spacePos + 1;
+ }
+ }
+ // Strip leading whitespace
+ size_t args_start = args.find_first_not_of(L" ");
+ args = (args_start != std::wstring::npos) ? args.substr(args_start) : L"";
+
+ // Define the path to the "scripts" directory
+ std::wstring scriptsDir = exeDir + L"\\scripts";
+
+ // Check if the "scripts" directory exists
+ DWORD attributes = GetFileAttributesW(scriptsDir.c_str());
+ if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ MessageBoxW(NULL, L"The 'scripts' directory does not exist. Please ensure it is in the same folder as the launcher.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Set the working directory to the "scripts" folder
+ if (!SetCurrentDirectoryW(scriptsDir.c_str())) {
+ MessageBoxW(NULL, L"Failed to set the working directory to 'scripts'.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Define the command to run and append arguments if present
+ std::wstring target;
+ if (!args.empty()) {
+ target = L"cmd.exe /c \"\"" LAUNCH_TARGET L"\" " + args + L"\"";
+ } else {
+ target = L"cmd.exe /c \"" LAUNCH_TARGET L"\"";
+ }
+
+ // Configure the process startup info
+ STARTUPINFO si = { sizeof(si) };
+ si.dwFlags = STARTF_USESHOWWINDOW; // Prevent the window from appearing
+ si.wShowWindow = SW_HIDE; // Hide the command window
+
+ PROCESS_INFORMATION pi = {};
+
+ // Start the process with CREATE_NO_WINDOW flag
+ if (!CreateProcessW(
+ NULL, // Application name (NULL because we pass the command in the command line)
+ &target[0], // Command line
+ NULL, // Process security attributes
+ NULL, // Thread security attributes
+ FALSE, // Inherit handles
+ CREATE_NO_WINDOW, // Flags to prevent creating a window
+ NULL, // Environment block (NULL to inherit parent)
+ NULL, // Current directory (NULL to use the parent process's current directory)
+ &si, // Startup info
+ &pi // Process information
+ )) {
+ MessageBoxW(NULL, L"Failed to launch the script.", L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Wait for the script to finish
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // Cleanup
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return 0;
+}
diff --git a/winpython/portable/launchers_building/launchers_src_original/LICENSE b/winpython/portable/launchers_building/launchers_src_original/LICENSE
new file mode 100644
index 00000000..b3fb976c
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src_original/LICENSE
@@ -0,0 +1,63 @@
+DataLab-WinPython license terms
+===============================
+
+DataLab-WinPython is a Python distribution for Windows:
+- Based on WinPython, a portable distribution of Python for Windows (see section I. below).
+- Including DataLab, an open-source platform for signal and image processing (see section II. below).
+
+I. - WinPython License Agreement (MIT License)
+----------------------------------------------
+
+Copyright (c) 2012 Pierre Raybaut, 2016+ WinPython team
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+II. - DataLab License Agreement (BSD 3-Clause License)
+------------------------------------------------------
+
+Copyright (c) 2023, DataLab Platform Developers.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/winpython/portable/launchers_building/launchers_src_original/build_one_launcher.bat b/winpython/portable/launchers_building/launchers_src_original/build_one_launcher.bat
new file mode 100644
index 00000000..c48374c4
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src_original/build_one_launcher.bat
@@ -0,0 +1,108 @@
+@echo on
+set icon_name=%1
+set LAUNCH_TARGET=%2
+set launcher_name=%3
+set subsystem=%4
+set destination=%5
+
+set icon_name=%icon_name:"=%
+set LAUNCH_TARGET=%LAUNCH_TARGET:"=%
+set launcher_name=%launcher_name:"=%
+set subsystem=%subsystem:"=%
+
+set ROOT_PATH=%~dp0..\
+set SCRIPT_PATH=%~dp0
+set TEMPO_PATH=%ROOT_PATH%launchers_temp
+set OUTPUT_DIR=%ROOT_PATH%launchers_%destination%
+
+set "ICON_FILE=%ROOT_PATH%icons\%icon_name%"
+set LAUNCHER_EXE=%OUTPUT_DIR%\%launcher_name%.exe
+
+
+:: Paths to template WINDOWS or CONSOLE
+set SOURCE_FILE=%SCRIPT_PATH%launcher_template_%subsystem%.cpp
+echo SOURCE_FILE=%SOURCE_FILE%
+
+set "RESOURCE_FILE=%TEMPO_PATH%\%icon_name%.rc"
+set "RESOURCE_OBJ=%TEMPO_PATH%\%icon_name%.res"
+
+
+:: create pDirectory if needed
+if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%"
+if not exist "%TEMPO_PATH%" mkdir "%TEMPO_PATH%"
+
+cd/d %TEMPO_PATH%
+
+:: Check if MSVC environment is already initialized
+if not defined VSINSTALLDIR (
+ echo Initializing MSVC environment...
+ call %VCVARS_PATH%
+ if errorlevel 1 (
+ echo [ERROR] Failed to initialize MSVC environment.
+ exit /b 1
+ )
+)
+
+@echo on
+
+:: Walk through .bat files in the current directory
+ echo Processing %icon_name%..
+ :: Stonebig: Remove previous .exe file
+ echo launcher_exe_action del /q "%LAUNCHER_EXE%"
+ if exist "%LAUNCHER_EXE%" (
+ move "%LAUNCHER_EXE%" "%LAUNCHER_EXE%.old.exe"
+ del /q "%LAUNCHER_EXE%.old.exe"
+ )
+ :: Stonebig: Remove intermediate .res and.rc file
+ if exist "%RESOURCE_OBJ%" (
+ move "%RESOURCE_OBJ%" "%RESOURCE_OBJ%.old.exe"
+ del /q "%RESOURCE_OBJ%.old.exe"
+ )
+ if exist "%RESOURCE_FILE%" (
+ move "%RESOURCE_FILE%" "%RESOURCE_FILE%.old.exe"
+ del /q "%RESOURCE_FILE%.old.exe"
+ )
+ :: Remove intermediate .obj file
+ del /q "launcher_template_%subsystem%.obj"
+
+ :: Check if the icon exists
+ if exist "%ICON_FILE%" (
+ echo Icon found: "%ICON_FILE%"
+ ) else (
+ echo No icon found for "%ICON_FILE%" stoping
+ pause
+ exit
+ )
+
+
+ :: Create resource file
+ echo Creating resource file...
+ > "%RESOURCE_FILE%" echo IDI_ICON1 ICON "%ICON_FILE%"
+ :: Compile resource
+ echo Compiling resource...
+ rc /fo "%RESOURCE_OBJ%" "%RESOURCE_FILE%"
+
+ :: Compile the launcher executable
+ echo Compiling launcher executable...
+ cl /EHsc /O2 /DUNICODE /W4 "%SOURCE_FILE%" "%RESOURCE_OBJ%" ^
+ /Fe"%LAUNCHER_EXE%%" ^
+ /DLAUNCH_TARGET=\"%LAUNCH_TARGET%\" ^
+ User32.lib ^
+ /link /SUBSYSTEM:%subsystem%
+
+
+ if errorlevel 1 (
+ echo [ERROR] Failed to build launcher for %LAUNCH_TARGET%
+ exit /b 1
+ )
+
+ if exist "%LAUNCHER_EXE%" (
+ echo [SUCCESS] Launcher created: "%LAUNCHER_EXE%""
+ ) else (
+ echo [ERROR] Failed to build launcher "%LAUNCHER_EXE%" from "%icon_name%" to call "%LAUNCH_TARGET%"
+ exit /b 1
+ )
+
+echo All launchers processed.
+rem exit /b 0
+
diff --git a/winpython/portable/launchers_building/launchers_src_original/launcher_template_CONSOLE.cpp b/winpython/portable/launchers_building/launchers_src_original/launcher_template_CONSOLE.cpp
new file mode 100644
index 00000000..93614b9e
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src_original/launcher_template_CONSOLE.cpp
@@ -0,0 +1,75 @@
+/*
+DataLab-WinPython launcher script
+---------------------------------
+
+Licensed under the terms of the BSD 3-Clause
+(see ./LICENSE for details)
+
+*/
+
+#include
+#include
+
+int main() {
+ // Get the path to the current executable
+ wchar_t exePath[MAX_PATH];
+ GetModuleFileNameW(NULL, exePath, MAX_PATH);
+
+ // Determine the directory of the executable
+ std::wstring exeDir = exePath;
+ exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/"));
+
+ // Define the path to the "scripts" directory
+ std::wstring scriptsDir = exeDir + L"\\scripts";
+
+ // Check if the "scripts" directory exists
+ DWORD attributes = GetFileAttributesW(scriptsDir.c_str());
+ if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ MessageBoxW(NULL, L"The 'scripts' directory does not exist. Please ensure it is in the same folder as the launcher.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Set the working directory to the "scripts" folder
+ if (!SetCurrentDirectoryW(scriptsDir.c_str())) {
+ MessageBoxW(NULL, L"Failed to set the working directory to 'scripts'.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Define the command to run
+ std::wstring target = L"cmd.exe /c \"" LAUNCH_TARGET L"\"";
+
+ // Configure the process startup info
+ STARTUPINFO si = { sizeof(si) };
+ si.dwFlags = STARTF_USESHOWWINDOW; // Prevent the window from appearing
+ si.wShowWindow = SW_HIDE; // Hide the command window
+
+ PROCESS_INFORMATION pi = {};
+
+ // Start the process without CREATE_NO_WINDOW flag to show the command window
+ if (!CreateProcessW(
+ NULL, // Application name (NULL because we pass the command in the command line)
+ &target[0], // Command line
+ NULL, // Process security attributes
+ NULL, // Thread security attributes
+ FALSE, // Inherit handles
+ 0, // No special flags
+ NULL, // Environment block (NULL to inherit parent)
+ NULL, // Current directory (NULL to use the parent process's current directory)
+ &si, // Startup info
+ &pi // Process information
+ )) {
+ MessageBoxW(NULL, L"Failed to launch the script.", L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Wait for the script to finish
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // Cleanup
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return 0;
+}
diff --git a/winpython/portable/launchers_building/launchers_src_original/launcher_template_WINDOWS.cpp b/winpython/portable/launchers_building/launchers_src_original/launcher_template_WINDOWS.cpp
new file mode 100644
index 00000000..9c878be6
--- /dev/null
+++ b/winpython/portable/launchers_building/launchers_src_original/launcher_template_WINDOWS.cpp
@@ -0,0 +1,75 @@
+/*
+DataLab-WinPython launcher script
+---------------------------------
+
+Licensed under the terms of the BSD 3-Clause
+(see ./LICENSE for details)
+
+*/
+
+#include
+#include
+
+int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/) {
+ // Get the path to the current executable
+ wchar_t exePath[MAX_PATH];
+ GetModuleFileNameW(NULL, exePath, MAX_PATH);
+
+ // Determine the directory of the executable
+ std::wstring exeDir = exePath;
+ exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/"));
+
+ // Define the path to the "scripts" directory
+ std::wstring scriptsDir = exeDir + L"\\scripts";
+
+ // Check if the "scripts" directory exists
+ DWORD attributes = GetFileAttributesW(scriptsDir.c_str());
+ if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ MessageBoxW(NULL, L"The 'scripts' directory does not exist. Please ensure it is in the same folder as the launcher.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Set the working directory to the "scripts" folder
+ if (!SetCurrentDirectoryW(scriptsDir.c_str())) {
+ MessageBoxW(NULL, L"Failed to set the working directory to 'scripts'.",
+ L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Define the command to run
+ std::wstring target = L"cmd.exe /c \"" LAUNCH_TARGET L"\"";
+
+ // Configure the process startup info
+ STARTUPINFO si = { sizeof(si) };
+ si.dwFlags = STARTF_USESHOWWINDOW; // Prevent the window from appearing
+ si.wShowWindow = SW_HIDE; // Hide the command window
+
+ PROCESS_INFORMATION pi = {};
+
+ // Start the process with CREATE_NO_WINDOW flag
+ if (!CreateProcessW(
+ NULL, // Application name (NULL because we pass the command in the command line)
+ &target[0], // Command line
+ NULL, // Process security attributes
+ NULL, // Thread security attributes
+ FALSE, // Inherit handles
+ CREATE_NO_WINDOW, // Flags to prevent creating a window
+ NULL, // Environment block (NULL to inherit parent)
+ NULL, // Current directory (NULL to use the parent process's current directory)
+ &si, // Startup info
+ &pi // Process information
+ )) {
+ MessageBoxW(NULL, L"Failed to launch the script.", L"Launcher Error", MB_ICONERROR);
+ return 1;
+ }
+
+ // Wait for the script to finish
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // Cleanup
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return 0;
+}
diff --git a/winpython/portable/launchers_final/IDLE (Python GUI).exe b/winpython/portable/launchers_final/IDLE (Python GUI).exe
new file mode 100644
index 00000000..65523199
Binary files /dev/null and b/winpython/portable/launchers_final/IDLE (Python GUI).exe differ
diff --git a/winpython/portable/launchers_final/Jupyter Lab.exe b/winpython/portable/launchers_final/Jupyter Lab.exe
new file mode 100644
index 00000000..93003fcb
Binary files /dev/null and b/winpython/portable/launchers_final/Jupyter Lab.exe differ
diff --git a/winpython/portable/launchers_final/Jupyter Notebook.exe b/winpython/portable/launchers_final/Jupyter Notebook.exe
new file mode 100644
index 00000000..28fdbea3
Binary files /dev/null and b/winpython/portable/launchers_final/Jupyter Notebook.exe differ
diff --git a/winpython/portable/launchers_final/Spyder reset.exe b/winpython/portable/launchers_final/Spyder reset.exe
new file mode 100644
index 00000000..21250f98
Binary files /dev/null and b/winpython/portable/launchers_final/Spyder reset.exe differ
diff --git a/winpython/portable/launchers_final/Spyder.exe b/winpython/portable/launchers_final/Spyder.exe
new file mode 100644
index 00000000..93b1a050
Binary files /dev/null and b/winpython/portable/launchers_final/Spyder.exe differ
diff --git a/winpython/portable/launchers_final/VS Code.exe b/winpython/portable/launchers_final/VS Code.exe
new file mode 100644
index 00000000..225decb4
Binary files /dev/null and b/winpython/portable/launchers_final/VS Code.exe differ
diff --git a/winpython/portable/launchers_final/WinPython Command Prompt.exe b/winpython/portable/launchers_final/WinPython Command Prompt.exe
new file mode 100644
index 00000000..e4e824c5
Binary files /dev/null and b/winpython/portable/launchers_final/WinPython Command Prompt.exe differ
diff --git a/winpython/portable/launchers_final/WinPython Control Panel.exe b/winpython/portable/launchers_final/WinPython Control Panel.exe
new file mode 100644
index 00000000..72a57a67
Binary files /dev/null and b/winpython/portable/launchers_final/WinPython Control Panel.exe differ
diff --git a/winpython/portable/launchers_final/WinPython Interpreter.exe b/winpython/portable/launchers_final/WinPython Interpreter.exe
new file mode 100644
index 00000000..dfa43135
Binary files /dev/null and b/winpython/portable/launchers_final/WinPython Interpreter.exe differ
diff --git a/winpython/portable/launchers_final/WinPython Powershell Prompt.exe b/winpython/portable/launchers_final/WinPython Powershell Prompt.exe
new file mode 100644
index 00000000..d4512f32
Binary files /dev/null and b/winpython/portable/launchers_final/WinPython Powershell Prompt.exe differ
diff --git a/winpython/portable/launchers_final/license.txt b/winpython/portable/launchers_final/license.txt
new file mode 100644
index 00000000..da461f3b
--- /dev/null
+++ b/winpython/portable/launchers_final/license.txt
@@ -0,0 +1,37 @@
+Note
+----
+
+WinPython components are distributed as they were received from
+their copyright holder, under their own copyright and/or license,
+and without any linking with each other.
+
+WinPython software collection (i.e. the collection of software,
+libraries and documents) is licensed under the terms of the
+following license agreement.
+
+
+WinPython License Agreement (MIT License)
+-----------------------------------------
+
+Copyright (c) 2012 Pierre Raybaut, 2016+ WinPython team
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/notebooks/docs/README.txt b/winpython/portable/launchers_final/notebooks/docs/README.txt
new file mode 100644
index 00000000..a0aab429
--- /dev/null
+++ b/winpython/portable/launchers_final/notebooks/docs/README.txt
@@ -0,0 +1 @@
+Examples are now to be found at github.com/winpython/winpython_afterdoc
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/WinPythonIni.py b/winpython/portable/launchers_final/scripts/WinPythonIni.py
new file mode 100644
index 00000000..cbcb640a
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/WinPythonIni.py
@@ -0,0 +1,167 @@
+import os
+import sys
+from pathlib import Path
+
+winpython_inidefault = r'''
+[debug]
+state = disabled
+[env.bat]
+#see https://github.com/winpython/winpython/issues/839
+#USERPROFILE = %HOME%
+SPYDER_CONFDIR = %HOME%\settings\.spyder-py3
+JUPYTER_DATA_DIR = %HOME%
+JUPYTER_CONFIG_DIR = %WINPYDIR%\etc\jupyter
+JUPYTER_CONFIG_PATH = %WINPYDIR%\etc\jupyter
+[inactive_environment_per_user]
+## > changing this segment to [active_environment_per_user] makes this segment of lines active
+HOME = %HOMEDRIVE%%HOMEPATH%\Documents\WinPython%WINPYVER%\settings
+USERPROFILE = %HOME%
+JUPYTER_DATA_DIR = %HOME%
+WINPYWORKDIR = %HOMEDRIVE%%HOMEPATH%\Documents\WinPython%WINPYVER%\Notebooks
+[inactive_environment_common]
+## > changing this segment to [inactive_environment_common] makes this segment of lines active
+USERPROFILE = %HOME%
+[environment]
+## > Uncomment lines to override environment variables
+#SPYDER_CONFDIR = %HOME%\settings\.spyder-py3
+#JULIA_HOME=%WINPYDIRBASE%\t\Julia\bin\
+#JULIA_EXE=julia.exe
+#JULIA=%JULIA_HOME%%JULIA_EXE%
+#JULIA_PKGDIR=%WINPYDIRBASE%\settings\.julia
+#QT_PLUGIN_PATH=%WINPYDIR%\Lib\site-packages\pyqt5_tools\Qt\plugins
+'''
+
+class WinPythonEnv:
+ editable_sections = {
+ "env.ini", "environment", "debug",
+ "active_environment_per_user", "active_environment_common"
+ }
+
+ def __init__(self, args=None):
+ self.args = args[:] if args is not None else sys.argv[1:]
+ self.env = dict(os.environ)
+ self._initialize_paths()
+ self.output_lines = []
+ # in case 1st parameter is a different WinPython.ini
+ if self.args and self.args[0].endswith("winpython.ini"):
+ self.winpython_ini = Path(self.args[0])
+ self.args = self.args[1:]
+ else:
+ self.winpython_ini = self.winpy_base / "settings" / "winpython.ini"
+ def _initialize_paths(self):
+ """we do what env.bat was doing"""
+ self.winpy_base = Path(Path(__file__).parent.parent).resolve()
+ self.home_dir = Path(self.winpy_base / 'settings')
+ self.winpy_dir = Path(sys.executable).parent
+ self.python_exe = Path(sys.executable)
+
+ def get_file(self, file_path: Path, default_content=None) -> str:
+ if not file_path.exists() and default_content:
+ file_path.parent.mkdir(parents=True, exist_ok=True)
+ file_path.write_text(default_content)
+ return file_path.read_text(encoding='utf-8')
+
+ def translate_vars(self, value: str) -> str:
+ """Replace %VAR% patterns with environment values."""
+ parts = value.split('%')
+ for i in range(1, len(parts), 2):
+ parts[i] = self.env.get(parts[i], parts[i])
+ return ''.join(parts)
+
+ def parse_ini_lines(self, lines):
+ """Parse ini lines and update environment variables."""
+ section = "env.ini"
+ for line in map(str.strip, lines):
+ if not line or line.startswith("#"):
+ continue
+ if line.startswith("["):
+ section = line.strip("[]")
+ continue
+ if "=" in line:
+ key, val = map(str.strip, line.split("=", 1))
+ val = self.translate_vars(val)
+ if section == "debug" and key == "state":
+ key = "WINPYDEBUG"
+ if section in self.editable_sections:
+ self.env[key] = val
+ self.output_lines.append(f"{key}={val}")
+
+ def setup_qt_conf(self):
+ """Create qt.conf files if missing for Qt-based packages."""
+ qt_conf_text = "[Paths]\nPrefix = .\nBinaries = .\n"
+ for subpkg in ("PyQt5", "PyQt6", "Pyside6"):
+ pkg_path = self.winpy_dir / "Lib" / "site-packages" / subpkg
+ if pkg_path.exists() and not (pkg_path / "qt.conf").exists():
+ (pkg_path / "qt.conf").write_text(qt_conf_text)
+
+
+ def setup_paths(self):
+ lines = [
+ f"WINPYDIRBASE={self.winpy_base}",
+ f"WINPYDIR={self.winpy_dir}",
+ f"PYTHON={self.python_exe}",
+ f"HOME={self.home_dir}",
+ f"WINPYWORKDIR={self.winpy_base / "Notebooks"}",
+ ]
+ if (self.winpy_dir / "Lib" / "site-packages" / "PyQt5" / "__init__.py").is_file():
+ lines.append("QT_API=pyqt5")
+ pandoc = self.winpy_base / "t" / "pandoc.exe"
+ if pandoc.is_file():
+ lines.append(f"PYPANDOC_PANDOC={pandoc}")
+ path_extra = f"{self.winpy_dir};{self.winpy_dir / 'Scripts'};{self.winpy_dir/ ".." / 't'};{self.winpy_dir / ".." / 'n'};"
+ if path_extra not in self.env.get('PATH', ''):
+ lines.append(f"PATH={path_extra}{self.env.get('PATH', '')}")
+ return lines
+
+
+ def ensure_dirs(self):
+ for key in ('HOME', 'WINPYWORKDIR', 'WINPYWORKDIR1'):
+ Path(self.env.get(key, self.home_dir)).mkdir(parents=True, exist_ok=True)
+ spyder_workdir = Path(self.env['HOME']) / f".spyder-py{sys.version_info[0]}" / "workingdir"
+ if not spyder_workdir.exists():
+ spyder_workdir.parent.mkdir(parents=True, exist_ok=True)
+ spyder_workdir.write_text(str(self.home_dir / "Notebooks"))
+
+ def determine_winpyworkdir1(self):
+ """Replicates original WINPYWORKDIR1 argument/path rules."""
+ winpyworkdir1 = Path(self.env['WINPYWORKDIR'])
+ if len(self.args) >= 1:
+ arg_path = Path(self.args[0])
+ if arg_path.is_file():
+ winpyworkdir1 = arg_path.parent
+ elif arg_path.is_dir():
+ winpyworkdir1 = arg_path
+ # If cwd differs from script dir (and not under 'scripts'), use cwd
+ cd_dir = Path(os.getcwd())
+ script_dir = Path(__file__).parent
+ if cd_dir != script_dir and cd_dir / "scripts" != script_dir:
+ winpyworkdir1 = cd_dir
+ self.env['WINPYWORKDIR1'] = str(winpyworkdir1)
+ self.output_lines.append(f"WINPYWORKDIR1={winpyworkdir1}")
+
+ def run(self):
+ # env.ini
+ env_ini_file = Path(__file__).parent / "env.ini"
+ if env_ini_file.is_file():
+ ini_content = self.get_file(env_ini_file)
+ self.parse_ini_lines(ini_content.splitlines())
+ # Set up variables and paths
+ self.parse_ini_lines(self.setup_paths())
+ # WINPYWORKDIR1 logic here
+ self.determine_winpyworkdir1()
+ # Load and parse ini files
+ ini_content = self.get_file(self.winpython_ini, winpython_inidefault)
+
+ self.parse_ini_lines(ini_content.splitlines())
+ # Ensure directories exist
+ self.ensure_dirs()
+ # Setup Qt conf files
+ self.setup_qt_conf()
+
+ for l in self.output_lines:
+ print(rf"set {l}" , end="&&")
+ # later_version ?
+ # p = subprocess.Popen(["start", "cmd", "/k", "set"], shell = True)
+
+if __name__ == "__main__":
+ WinPythonEnv().run()
diff --git a/winpython/portable/launchers_final/scripts/WinPython_PS_Prompt.ps1 b/winpython/portable/launchers_final/scripts/WinPython_PS_Prompt.ps1
new file mode 100644
index 00000000..d35aaa48
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/WinPython_PS_Prompt.ps1
@@ -0,0 +1,62 @@
+### WinPython_PS_Prompt.ps1 ###
+$0 = $myInvocation.MyCommand.Definition
+$dp0 = [System.IO.Path]::GetDirectoryName($0)
+
+# default if env.cfg fails
+$env:WINPYthon_subdirectory_name = "python"
+$env:WINPYthon_exe = "python.exe"
+# Define the path to the config file
+Get-Content (${PSScriptRoot} +"\env.ini") | ForEach-Object {
+ $parts = $_ -split '=', 2
+ if ($parts.Count -eq 2) {
+ Set-Variable -Name ($parts[0]).Trim() -Value $parts[1].Trim() -Scope Global
+ }
+}
+
+# $env:PYTHONUTF8 = 1 would create issues in "movable" patching
+$env:WINPYDIRBASE = "$dp0\.."
+# get a normalize path
+# http://stackoverflow.com/questions/1645843/resolve-absolute-path-from-relative-path-and-or-file-name
+$env:WINPYDIRBASE = [System.IO.Path]::GetFullPath( $env:WINPYDIRBASE )
+
+# avoid double_init (will only resize screen)
+if (-not ($env:WINPYDIR -eq [System.IO.Path]::GetFullPath( $env:WINPYDIRBASE+"\{self.python_dir_name}")) ) {
+$env:WINPYDIR = $env:WINPYDIRBASE+ "\" +$env:WINPYthon_subdirectory_name
+# 2019-08-25 pyjulia needs absolutely a variable PYTHON=%WINPYDIR%python.exe
+$env:PYTHON = $env:WINPYthon_exe
+
+$env:WINPYVER = $env:WINPYVER
+# rem 2023-02-12 try utf-8 on console
+# rem see https://github.com/pypa/pip/issues/11798#issuecomment-1427069681
+$env:PYTHONIOENCODING = "utf-8"
+
+$env:HOME = "$env:WINPYDIRBASE\settings"
+
+$env:WINPYDIRBASE = ""
+$env:JUPYTER_DATA_DIR = "$env:HOME"
+
+if (-not $env:PATH.ToLower().Contains(";"+ $env:WINPYDIR.ToLower()+ ";")) {
+ $env:PATH = "$env:WINPYDIR\\Lib\site-packages\PyQt5;$env:WINPYDIR\\;$env:WINPYDIR\\DLLs;$env:WINPYDIR\\Scripts;$env:WINPYDIR\\..\t;$env:WINPYDIR\\..\n;$env:path" }
+
+
+#rem force default pyqt5 kit for Spyder if PyQt5 module is there
+if (Test-Path "$env:WINPYDIR\Lib\site-packages\PyQt5\__init__.py") { $env:QT_API = "pyqt5" }
+
+# PyQt5 qt.conf creation and winpython.ini creation done via Winpythonini.py (called per env_for_icons.bat for now)
+# Start-Process -FilePath $env:PYTHON -ArgumentList ($env:WINPYDIRBASE + '\scripts\WinPythonIni.py')
+
+
+### Set-WindowSize
+
+Function Set-WindowSize {
+Param([int]$x=$host.ui.rawui.windowsize.width,
+ [int]$y=$host.ui.rawui.windowsize.heigth,
+ [int]$buffer=$host.UI.RawUI.BufferSize.heigth)
+ $buffersize = new-object System.Management.Automation.Host.Size($x,$buffer)
+ $host.UI.RawUI.BufferSize = $buffersize
+ $size = New-Object System.Management.Automation.Host.Size($x,$y)
+ $host.ui.rawui.WindowSize = $size
+}
+# Windows10 yelling at us with 150 40 6000
+# Set-WindowSize 195 40 6000
+}
diff --git a/winpython/portable/launchers_final/scripts/activate.bat b/winpython/portable/launchers_final/scripts/activate.bat
new file mode 100644
index 00000000..e52886af
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/activate.bat
@@ -0,0 +1,2 @@
+@echo off
+call "%~dp0env.bat" %*
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/cmd.bat b/winpython/portable/launchers_final/scripts/cmd.bat
new file mode 100644
index 00000000..fc76541f
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/cmd.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+cmd.exe /k
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/cmd_ps.bat b/winpython/portable/launchers_final/scripts/cmd_ps.bat
new file mode 100644
index 00000000..c6fa79a4
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/cmd_ps.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat"
+Powershell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy RemoteSigned -noexit -File ""%~dp0WinPython_PS_Prompt.ps1""'}"
diff --git a/winpython/portable/launchers_final/scripts/env.bat b/winpython/portable/launchers_final/scripts/env.bat
new file mode 100644
index 00000000..324d971b
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/env.bat
@@ -0,0 +1,26 @@
+@echo off
+rem read init variables
+FOR /F "usebackq tokens=1,2 delims==" %%G IN ("%~dp0env.ini") DO (set %%G=%%H)
+
+set WINPYDIRBASE=%~dp0..
+
+rem get a normalized path
+set WINPYDIRBASETMP=%~dp0..
+pushd %WINPYDIRBASETMP%
+set WINPYDIRBASE=%__CD__%
+if "%WINPYDIRBASE:~-1%"=="\" set WINPYDIRBASE=%WINPYDIRBASE:~0,-1%
+set WINPYDIRBASETMP=
+popd
+
+set WINPYDIR=%WINPYDIRBASE%\python
+set PYTHON=%WINPYDIR%\python.exe
+
+set PYTHONIOENCODING=utf-8
+set HOME=%WINPYDIRBASE%\settings
+
+rem Remove all double quotes
+set PATH_CLEANED=%PATH:"=%
+echo ";%PATH_CLEANED%;" | %WINDIR%\system32\find.exe /C /I ";%WINPYDIR%\;" >nul
+if %ERRORLEVEL% NEQ 0 set "PATH=%WINPYDIR%\;%WINPYDIR%\Scripts;%WINPYDIR%\..\t;%WINPYDIR%\..\n;%PATH%"
+
+set PATH_CLEANED=
diff --git a/winpython/portable/launchers_final/scripts/env_for_icons.bat b/winpython/portable/launchers_final/scripts/env_for_icons.bat
new file mode 100644
index 00000000..19df384c
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/env_for_icons.bat
@@ -0,0 +1,7 @@
+@echo off
+FOR /F "delims=" %%i IN ('""%~dp0..\python\python.exe" "%~dp0WinpythonIni.py" %* "') DO set winpythontoexec=%%i
+%winpythontoexec%set winpythontoexec=
+
+rem Change of directory only if we are in a launcher directory
+if "%__CD__%scripts\"=="%~dp0" cd/D %WINPYWORKDIR1%
+if "%__CD__%"=="%~dp0" cd/D %WINPYWORKDIR1%
diff --git a/winpython/portable/launchers_final/scripts/python.bat b/winpython/portable/launchers_final/scripts/python.bat
new file mode 100644
index 00000000..1e8fea0b
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/python.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+"%WINPYDIR%\python.exe" %*
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/readme.txt b/winpython/portable/launchers_final/scripts/readme.txt
new file mode 100644
index 00000000..11592357
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/readme.txt
@@ -0,0 +1,3 @@
+These batch files are required to run WinPython icons.
+These files should help the user writing his/her own
+The environment variables are set-up in 'env.bat' and 'env_for_icons.bat'.
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/spyder_reset.bat b/winpython/portable/launchers_final/scripts/spyder_reset.bat
new file mode 100644
index 00000000..89cb78c8
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/spyder_reset.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat"
+"%WINPYDIR%\scripts\spyder.exe" --reset %*
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/upgrade_pip.bat b/winpython/portable/launchers_final/scripts/upgrade_pip.bat
new file mode 100644
index 00000000..4443ed16
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/upgrade_pip.bat
@@ -0,0 +1,7 @@
+@echo off
+call "%~dp0env.bat"
+echo this will upgrade pip with latest version, then patch it for WinPython portability ok ?
+pause
+"%WINPYDIR%\python.exe" -m pip install --upgrade pip
+"%WINPYDIR%\python.exe" -c "from wppm import wppm;dist=wppm.Distribution(r'%WINPYDIR%');dist.patch_standard_packages('pip', to_movable=True)
+pause
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/winidle.bat b/winpython/portable/launchers_final/scripts/winidle.bat
new file mode 100644
index 00000000..b3f734d9
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/winidle.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+"%WINPYDIR%\python.exe" -m idlelib %*
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/winipython_notebook.bat b/winpython/portable/launchers_final/scripts/winipython_notebook.bat
new file mode 100644
index 00000000..8123c5ee
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/winipython_notebook.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+"%WINPYDIR%\python.exe" -m jupyter notebook %*
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/winjupyter_lab.bat b/winpython/portable/launchers_final/scripts/winjupyter_lab.bat
new file mode 100644
index 00000000..b0ed37f9
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/winjupyter_lab.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+"%WINPYDIR%\python.exe" -m jupyter lab %*
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/winpython.bat b/winpython/portable/launchers_final/scripts/winpython.bat
new file mode 100644
index 00000000..2a0706ec
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/winpython.bat
@@ -0,0 +1,8 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+rem backward compatibility for non-ptpython users
+if exist "%WINPYDIR%\Lib\site-packages\ptpython" (
+ "%WINPYDIR%\python.exe" -m ptpython %*
+) else (
+ "%WINPYDIR%\python.exe" %*
+)
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/winspyder.bat b/winpython/portable/launchers_final/scripts/winspyder.bat
new file mode 100644
index 00000000..1a843ca0
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/winspyder.bat
@@ -0,0 +1,5 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+rem "%WINPYDIR%\scripts\spyder.exe" %* -w "%WINPYWORKDIR1%"
+"%WINPYDIR%\scripts\spyder.exe" %*
+
diff --git a/winpython/portable/launchers_final/scripts/winvscode.bat b/winpython/portable/launchers_final/scripts/winvscode.bat
new file mode 100644
index 00000000..d9697b89
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/winvscode.bat
@@ -0,0 +1,10 @@
+@echo off
+call "%~dp0env_for_icons.bat"
+if exist "%WINPYDIR%\..\t\vscode\code.exe" (
+ "%WINPYDIR%\..\t\vscode\code.exe" %*
+) else (
+if exist "%LOCALAPPDATA%\Programs\Microsoft VS Code\code.exe" (
+ "%LOCALAPPDATA%\Programs\Microsoft VS Code\code.exe" %*
+) else (
+ code %*
+))
\ No newline at end of file
diff --git a/winpython/portable/launchers_final/scripts/wpcp.bat b/winpython/portable/launchers_final/scripts/wpcp.bat
new file mode 100644
index 00000000..6dd22056
--- /dev/null
+++ b/winpython/portable/launchers_final/scripts/wpcp.bat
@@ -0,0 +1,3 @@
+@echo off
+call "%~dp0env_for_icons.bat" %*
+cmd.exe /k "echo wppm & "%WINPYDIR%\python.exe" -m wppm" %*
\ No newline at end of file
diff --git a/winpython/py3compat.py b/winpython/py3compat.py
deleted file mode 100644
index 0705d074..00000000
--- a/winpython/py3compat.py
+++ /dev/null
@@ -1,271 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2012-2013 Pierre Raybaut
-# Licensed under the terms of the MIT License
-# (see spyderlib/__init__.py for details)
-
-"""
-spyderlib.py3compat
--------------------
-
-Transitional module providing compatibility functions intended to help
-migrating from Python 2 to Python 3.
-
-This module should be fully compatible with:
- * Python >=v2.6
- * Python 3
-"""
-
-from __future__ import print_function
-
-import sys
-import os
-
-PY2 = sys.version[0] == '2'
-PY3 = sys.version[0] == '3'
-
-
-# ==============================================================================
-# Data types
-# ==============================================================================
-if PY2:
- # Python 2
- TEXT_TYPES = (str, unicode)
- INT_TYPES = (int, long)
-else:
- # Python 3
- TEXT_TYPES = (str,)
- INT_TYPES = (int,)
-NUMERIC_TYPES = tuple(list(INT_TYPES) + [float, complex])
-
-
-# ==============================================================================
-# Renamed/Reorganized modules
-# ==============================================================================
-if PY2:
- # Python 2
- import __builtin__ as builtins
- import ConfigParser as configparser
-
- try:
- import _winreg as winreg
- except ImportError:
- pass
- from sys import maxint as maxsize
-
- try:
- import CStringIO as io
- except ImportError:
- import StringIO as io
- try:
- import cPickle as pickle
- except ImportError:
- import pickle
- from UserDict import DictMixin as MutableMapping
- import thread as _thread
- import repr as reprlib
-else:
- # Python 3
- import builtins
- import configparser
-
- try:
- import winreg
- except ImportError:
- pass
- from sys import maxsize
- import io
- import pickle
- try: # Python 3.8 and more
- from collections.abc import MutableMapping
- except ImportError:
- from collections import MutableMapping
- import _thread
- import reprlib
-# ==============================================================================
-# Strings
-# ==============================================================================
-if PY2:
- # Python 2
- import codecs
-
- def u(obj):
- """Make unicode object"""
- return codecs.unicode_escape_decode(obj)[0]
-
-
-else:
- # Python 3
- def u(obj):
- """Return string as it is"""
- return obj
-
-
-def is_text_string(obj):
- """Return True if `obj` is a text string, False if it is anything else,
- like binary data (Python 3) or QString (Python 2, PyQt API #1)"""
- if PY2:
- # Python 2
- return isinstance(obj, basestring)
- else:
- # Python 3
- return isinstance(obj, str)
-
-
-def is_binary_string(obj):
- """Return True if `obj` is a binary string, False if it is anything else"""
- if PY2:
- # Python 2
- return isinstance(obj, str)
- else:
- # Python 3
- return isinstance(obj, bytes)
-
-
-def is_string(obj):
- """Return True if `obj` is a text or binary Python string object,
- False if it is anything else, like a QString (Python 2, PyQt API #1)"""
- return is_text_string(obj) or is_binary_string(obj)
-
-
-def is_unicode(obj):
- """Return True if `obj` is unicode"""
- if PY2:
- # Python 2
- return isinstance(obj, unicode)
- else:
- # Python 3
- return isinstance(obj, str)
-
-
-def to_text_string(obj, encoding=None):
- """Convert `obj` to (unicode) text string"""
- if PY2:
- # Python 2
- if encoding is None:
- return unicode(obj)
- else:
- return unicode(obj, encoding)
- else:
- # Python 3
- if encoding is None:
- return str(obj)
- elif isinstance(obj, str):
- # In case this function is not used properly, this could happen
- return obj
- else:
- return str(obj, encoding)
-
-
-def to_binary_string(obj, encoding=None):
- """Convert `obj` to binary string (bytes in Python 3, str in Python 2)"""
- if PY2:
- # Python 2
- if encoding is None:
- return str(obj)
- else:
- return obj.encode(encoding)
- else:
- # Python 3
- return bytes(
- obj, 'utf-8' if encoding is None else encoding
- )
-
-
-# ==============================================================================
-# Function attributes
-# ==============================================================================
-def get_func_code(func):
- """Return function code object"""
- if PY2:
- # Python 2
- return func.func_code
- else:
- # Python 3
- return func.__code__
-
-
-def get_func_name(func):
- """Return function name"""
- if PY2:
- # Python 2
- return func.func_name
- else:
- # Python 3
- return func.__name__
-
-
-def get_func_defaults(func):
- """Return function default argument values"""
- if PY2:
- # Python 2
- return func.func_defaults
- else:
- # Python 3
- return func.__defaults__
-
-
-# ==============================================================================
-# Special method attributes
-# ==============================================================================
-def get_meth_func(obj):
- """Return method function object"""
- if PY2:
- # Python 2
- return obj.im_func
- else:
- # Python 3
- return obj.__func__
-
-
-def get_meth_class_inst(obj):
- """Return method class instance"""
- if PY2:
- # Python 2
- return obj.im_self
- else:
- # Python 3
- return obj.__self__
-
-
-def get_meth_class(obj):
- """Return method class"""
- if PY2:
- # Python 2
- return obj.im_class
- else:
- # Python 3
- return obj.__self__.__class__
-
-
-# ==============================================================================
-# Misc.
-# ==============================================================================
-if PY2:
- # Python 2
- input = raw_input
- getcwd = os.getcwdu
- cmp = cmp
- import string
-
- str_lower = string.lower
- from itertools import izip_longest as zip_longest
-else:
- # Python 3
- input = input
- getcwd = os.getcwd
-
- def cmp(a, b):
- return (a > b) - (a < b)
-
- str_lower = str.lower
- from itertools import zip_longest
-
-
-def qbytearray_to_str(qba):
- """Convert QByteArray object to str in a way compatible with Python 2/3"""
- return str(bytes(qba.toHex().data()).decode())
-
-
-if __name__ == '__main__':
- pass
diff --git a/winpython/qthelpers.py b/winpython/qthelpers.py
deleted file mode 100644
index a7ac4ee3..00000000
--- a/winpython/qthelpers.py
+++ /dev/null
@@ -1,302 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2009-2011 Pierre Raybaut
-# Licensed under the terms of the MIT License
-# (copied from Spyder source code [spyderlib.qt])
-#
-# Qt5 migration would not have been possible without
-# 2014-2015 Spyder Development Team work
-# (MIT License too, same parent project)
-
-"""Qt utilities"""
-
-# winpython.qt becomes winpython._vendor.qtpy
-from winpython._vendor.qtpy.QtWidgets import (
- QAction,
- QStyle,
- QWidget,
- QApplication,
- QLabel,
- QVBoxLayout,
- QHBoxLayout,
- QLineEdit,
- QMenu,
- QToolButton,
-)
-
-from winpython._vendor.qtpy.QtGui import (
- QIcon,
- QKeyEvent,
- QKeySequence,
- QPixmap,
-)
-
-from winpython._vendor.qtpy.QtCore import (
- Signal,
- QObject,
- Qt,
- QLocale,
- QTranslator,
- QLibraryInfo,
- QEvent,
- Slot,
-)
-from winpython._vendor.qtpy.compat import (
- to_qvariant,
- from_qvariant,
-)
-
-import os
-import re
-import os.path as osp
-from pathlib import Path
-import sys
-
-# Local import
-from winpython import config
-from winpython.py3compat import (
- is_text_string,
- to_text_string,
-)
-
-
-def get_icon(name):
- """Return QIcon from icon name"""
- # return QIcon(osp.join(config.IMAGE_PATH, name))
- return QIcon(str(Path(config.IMAGE_PATH) / name))
-
-
-class MacApplication(QApplication):
- """Subclass to be able to open external files with our Mac app"""
-
- open_external_file = Signal(str)
-
- def __init__(self, *args):
- QApplication.__init__(self, *args)
-
- def event(self, event):
- if event.type() == QEvent.FileOpen:
- fname = str(event.file())
- # PyQt4 old SIGNAL: self.emit(SIGNAL('open_external_file(QString)'), fname)
- self.open_external_file.emit(fname)
- return QApplication.event(self, event)
-
-
-def qapplication(translate=True):
- """Return QApplication instance
- Creates it if it doesn't already exist"""
- if (
- sys.platform == "darwin"
- and 'Spyder.app' in __file__
- ):
- SpyderApplication = MacApplication
- else:
- SpyderApplication = QApplication
- app = SpyderApplication.instance()
- if not app:
- # Set Application name for Gnome 3
- # https://groups.google.com/forum/#!topic/pyside/24qxvwfrRDs
- app = SpyderApplication(['Spyder'])
- if translate:
- install_translator(app)
- return app
-
-
-def file_uri(fname):
- """Select the right file uri scheme according to the operating system"""
- if os.name == 'nt':
- # Local file
- if re.search(r'^[a-zA-Z]:', fname):
- return 'file:///' + fname
- # UNC based path
- else:
- return 'file://' + fname
- else:
- return 'file://' + fname
-
-
-QT_TRANSLATOR = None
-
-
-def install_translator(qapp):
- """Install Qt translator to the QApplication instance"""
- global QT_TRANSLATOR
- if QT_TRANSLATOR is None:
- qt_translator = QTranslator()
- if qt_translator.load(
- "qt_" + QLocale.system().name(),
- QLibraryInfo.location(
- QLibraryInfo.TranslationsPath
- ),
- ):
- QT_TRANSLATOR = (
- qt_translator
- ) # Keep reference alive
- if QT_TRANSLATOR is not None:
- qapp.installTranslator(QT_TRANSLATOR)
-
-
-def keybinding(attr):
- """Return keybinding"""
- ks = getattr(QKeySequence, attr)
- return from_qvariant(
- QKeySequence.keyBindings(ks)[0], str
- )
-
-
-def _process_mime_path(path, extlist):
- if path.startswith(r"file://"):
- if os.name == 'nt':
- # On Windows platforms, a local path reads: file:///c:/...
- # and a UNC based path reads like: file://server/share
- if path.startswith(
- r"file:///"
- ): # this is a local path
- path = path[8:]
- else: # this is a unc path
- path = path[5:]
- else:
- path = path[7:]
- if osp.exists(path):
- if (
- extlist is None
- or osp.splitext(path)[1] in extlist
- ):
- return path
-
-
-def mimedata2url(source, extlist=None):
- """
- Extract url list from MIME data
- extlist: for example ('.py', '.pyw')
- """
- pathlist = []
- if source.hasUrls():
- for url in source.urls():
- path = _process_mime_path(
- to_text_string(url.toString()), extlist
- )
- if path is not None:
- pathlist.append(path)
- elif source.hasText():
- for rawpath in to_text_string(
- source.text()
- ).splitlines():
- path = _process_mime_path(rawpath, extlist)
- if path is not None:
- pathlist.append(path)
- if pathlist:
- return pathlist
-
-
-def action2button(
- action,
- autoraise=True,
- text_beside_icon=False,
- parent=None,
-):
- """Create a QToolButton directly from a QAction object"""
- if parent is None:
- parent = action.parent()
- button = QToolButton(parent)
- button.setDefaultAction(action)
- button.setAutoRaise(autoraise)
- if text_beside_icon:
- button.setToolButtonStyle(
- Qt.ToolButtonTextBesideIcon
- )
- return button
-
-
-def toggle_actions(actions, enable):
- """Enable/disable actions"""
- if actions is not None:
- for action in actions:
- if action is not None:
- action.setEnabled(enable)
-
-
-def create_action(
- parent,
- text,
- shortcut=None,
- icon=None,
- tip=None,
- toggled=None,
- triggered=None,
- data=None,
- menurole=None,
- context=Qt.WindowShortcut,
-):
- """Create a QAction"""
- action = QAction(text, parent)
- if triggered is not None:
- # PyQt4 old SIGNAL: parent.connect(action, SIGNAL("triggered()"), triggered)
- action.triggered.connect(triggered)
- if toggled is not None:
- # PyQt4 old SIGNAL: parent.connect(action, SIGNAL("toggled(bool)"), toggled)
- action.toggled.connect(toggled)
- action.setCheckable(True)
- if icon is not None:
- if is_text_string(icon):
- icon = get_icon(icon)
- action.setIcon(icon)
- if shortcut is not None:
- action.setShortcut(shortcut)
- if tip is not None:
- action.setToolTip(tip)
- action.setStatusTip(tip)
- if data is not None:
- action.setData(to_qvariant(data))
- if menurole is not None:
- action.setMenuRole(menurole)
- # TODO: Hard-code all shortcuts and choose context=Qt.WidgetShortcut
- # (this will avoid calling shortcuts from another dockwidget
- # since the context thing doesn't work quite well with these widgets)
- action.setShortcutContext(context)
- return action
-
-
-def add_actions(target, actions, insert_before=None):
- """Add actions to a menu"""
- previous_action = None
- target_actions = list(target.actions())
- if target_actions:
- previous_action = target_actions[-1]
- if previous_action.isSeparator():
- previous_action = None
- for action in actions:
- if (action is None) and (
- previous_action is not None
- ):
- if insert_before is None:
- target.addSeparator()
- else:
- target.insertSeparator(insert_before)
- elif isinstance(action, QMenu):
- if insert_before is None:
- target.addMenu(action)
- else:
- target.insertMenu(insert_before, action)
- elif isinstance(action, QAction):
- if insert_before is None:
- target.addAction(action)
- else:
- target.insertAction(insert_before, action)
- previous_action = action
-
-
-def get_std_icon(name, size=None):
- """Get standard platform icon
- Call 'show_std_icons()' for details"""
- if not name.startswith('SP_'):
- name = 'SP_' + name
- icon = (
- QWidget()
- .style()
- .standardIcon(getattr(QStyle, name))
- )
- if size is None:
- return icon
- else:
- return QIcon(icon.pixmap(size, size))
diff --git a/winpython/register_python.py b/winpython/register_python.py
deleted file mode 100644
index 852ba033..00000000
--- a/winpython/register_python.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python
-import sys
-from winpython import associate, utils
-from argparse import ArgumentParser
-
-parser = ArgumentParser(description="Register Python file extensions, icons "\
- "and Windows explorer context menu to a target "\
- "Python distribution.")
-try:
- str_type = unicode
-except NameError:
- str_type = str
-parser.add_argument('--target', metavar='path', type=str,
- default=sys.prefix,
- help='path to the target Python distribution')
-parser.add_argument('--all', dest='all', action='store_const',
- const=True, default=False,
- help='register to all users, requiring administrative '\
- 'privileges (default: register to current user only)')
-args = parser.parse_args()
-
-print(args.target)
-if utils.is_python_distribution(args.target):
- associate.register(args.target, current=not args.all)
-else:
- raise WindowsError("Invalid Python distribution %s" % args.target)
diff --git a/winpython/unregister_python.py b/winpython/unregister_python.py
deleted file mode 100644
index 93d7684d..00000000
--- a/winpython/unregister_python.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python
-import sys
-from winpython import associate, utils
-from argparse import ArgumentParser
-
-parser = ArgumentParser(description="unRegister Python file extensions, icons "\
- "and Windows explorer context menu to a target "\
- "Python distribution.")
-try:
- str_type = unicode
-except NameError:
- str_type = str
-parser.add_argument('--target', metavar='path', type=str,
- default=sys.prefix,
- help='path to the target Python distribution')
-parser.add_argument('--all', dest='all', action='store_const',
- const=True, default=False,
- help='unregister to all users, requiring administrative '\
- 'privileges (default: register to current user only)')
-args = parser.parse_args()
-
-print(args.target)
-if utils.is_python_distribution(args.target):
- associate.unregister(args.target, current=not args.all)
-else:
- raise WindowsError("Invalid Python distribution %s" % args.target)
diff --git a/winpython/utils.py b/winpython/utils.py
deleted file mode 100644
index 561cabe4..00000000
--- a/winpython/utils.py
+++ /dev/null
@@ -1,916 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2012 Pierre Raybaut
-# Licensed under the terms of the MIT License
-# (see winpython/__init__.py for details)
-
-"""
-WinPython utilities
-
-Created on Tue Aug 14 14:08:40 2012
-"""
-
-from __future__ import print_function
-
-import os
-import os.path as osp
-from pathlib import Path
-import subprocess
-import re
-import tarfile
-import zipfile
-import tempfile
-import shutil
-import atexit
-import sys
-import stat
-import locale
-import io
-
-# Local imports
-from winpython.py3compat import winreg
-
-def get_python_executable(path = None):
- """return the python executable"""
- my_path = sys.executable if path == None else path # default = current one
- my_path = my_path if osp.isdir(my_path) else osp.dirname(my_path)
- exec_py = os.path.join(my_path, 'python.exe')
- exec_pypy = os.path.join(my_path, 'pypy3.exe') # PyPy !
- # PyPy >=7.3.6 3.8 aligns to python.exe and Lib\site-packages
- #python_executable = exec_pypy if osp.isfile(exec_pypy) else exec_py
- python_executable = exec_py if osp.isfile(exec_py) else exec_pypy
- return python_executable
-
-def get_site_packages_path(path = None):
- """return the python site-packages"""
- my_path = sys.executable if path == None else path # default = current one
- my_path = my_path if osp.isdir(my_path) else osp.dirname(my_path)
- site_py = os.path.join(my_path, 'Lib', 'site-packages')
- site_pypy = os.path.join(my_path, 'site-packages') # PyPy !!
- site_packages_path = site_pypy if osp.isfile(site_pypy) else site_py
- return site_packages_path
-
-def onerror(function, path, excinfo):
- """Error handler for `shutil.rmtree`.
-
- If the error is due to an access error (read-only file), it
- attempts to add write permission and then retries.
- If the error is for another reason, it re-raises the error.
-
- Usage: `shutil.rmtree(path, onerror=onerror)"""
- if not os.access(path, os.W_OK):
- # Is the error an access error?
- os.chmod(path, stat.S_IWUSR)
- function(path)
- else:
- raise
-
-
-# Exact copy of 'spyderlib.utils.programs.is_program_installed' function
-def is_program_installed(basename):
- """Return program absolute path if installed in PATH
- Otherwise, return None"""
- for path in os.environ["PATH"].split(os.pathsep):
- # abspath = osp.join(path, basename)
- abspath = str(Path(path) / basename)
- if osp.isfile(abspath):
- return abspath
-
-
-# =============================================================================
-# Environment variables
-# =============================================================================
-def get_env(name, current=True):
- """Return HKCU/HKLM environment variable name and value
-
- For example, get_user_env('PATH') may returns:
- ('Path', u'C:\\Program Files\\Intel\\WiFi\\bin\\')"""
- root = (
- winreg.HKEY_CURRENT_USER
- if current
- else winreg.HKEY_LOCAL_MACHINE
- )
- key = winreg.OpenKey(root, "Environment")
- for index in range(0, winreg.QueryInfoKey(key)[1]):
- try:
- value = winreg.EnumValue(key, index)
- if value[0].lower() == name.lower():
- # Return both value[0] and value[1] because value[0] could be
- # different from name (lowercase/uppercase)
- return value[0], value[1]
- except:
- break
-
-
-def set_env(name, value, current=True):
- """Set HKCU/HKLM environment variables"""
- root = (
- winreg.HKEY_CURRENT_USER
- if current
- else winreg.HKEY_LOCAL_MACHINE
- )
- key = winreg.OpenKey(root, "Environment")
- try:
- _x, key_type = winreg.QueryValueEx(key, name)
- except WindowsError:
- key_type = winreg.REG_EXPAND_SZ
- key = winreg.OpenKey(
- root, "Environment", 0, winreg.KEY_SET_VALUE
- )
- winreg.SetValueEx(key, name, 0, key_type, value)
- from win32gui import SendMessageTimeout
- from win32con import (
- HWND_BROADCAST,
- WM_SETTINGCHANGE,
- SMTO_ABORTIFHUNG,
- )
-
- SendMessageTimeout(
- HWND_BROADCAST,
- WM_SETTINGCHANGE,
- 0,
- "Environment",
- SMTO_ABORTIFHUNG,
- 5000,
- )
-
-
-#==============================================================================
-# https://stackoverflow.com/questions/580924/how-to-access-a-files-properties-on-windows
-def getFileProperties(fname):
-#==============================================================================
- """
- Read all properties of the given file return them as a dictionary.
- """
- import win32api
- propNames = ('Comments', 'InternalName', 'ProductName',
- 'CompanyName', 'LegalCopyright', 'ProductVersion',
- 'FileDescription', 'LegalTrademarks', 'PrivateBuild',
- 'FileVersion', 'OriginalFilename', 'SpecialBuild')
-
- props = {'FixedFileInfo': None, 'StringFileInfo': None, 'FileVersion': None}
-
- try:
- # backslash as parm returns dictionary of numeric info corresponding to VS_FIXEDFILEINFO struc
- fixedInfo = win32api.GetFileVersionInfo(fname, '\\')
- props['FixedFileInfo'] = fixedInfo
- props['FileVersion'] = "%d.%d.%d.%d" % (fixedInfo['FileVersionMS'] / 65536,
- fixedInfo['FileVersionMS'] % 65536, fixedInfo['FileVersionLS'] / 65536,
- fixedInfo['FileVersionLS'] % 65536)
-
- # \VarFileInfo\Translation returns list of available (language, codepage)
- # pairs that can be used to retreive string info. We are using only the first pair.
- lang, codepage = win32api.GetFileVersionInfo(fname, '\\VarFileInfo\\Translation')[0]
-
- # any other must be of the form \StringfileInfo\%04X%04X\parm_name, middle
- # two are language/codepage pair returned from above
-
- strInfo = {}
- for propName in propNames:
- strInfoPath = u'\\StringFileInfo\\%04X%04X\\%s' % (lang, codepage, propName)
- ## print str_info
- strInfo[propName] = win32api.GetFileVersionInfo(fname, strInfoPath)
-
- props['StringFileInfo'] = strInfo
- except:
- pass
-
- return props
-# =============================================================================
-# Shortcuts, start menu
-# =============================================================================
-
-
-def get_special_folder_path(path_name):
- """Return special folder path"""
- from win32com.shell import shell, shellcon
-
- for maybe in """
- CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA
- CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY
- CSIDL_DESKTOPDIRECTORY CSIDL_COMMON_STARTUP CSIDL_STARTUP
- CSIDL_COMMON_PROGRAMS CSIDL_PROGRAMS CSIDL_PROGRAM_FILES_COMMON
- CSIDL_PROGRAM_FILES CSIDL_FONTS""".split():
- if maybe == path_name:
- csidl = getattr(shellcon, maybe)
- return shell.SHGetSpecialFolderPath(
- 0, csidl, False
- )
- raise ValueError(
- "%s is an unknown path ID" % (path_name,)
- )
-
-
-def get_winpython_start_menu_folder(current=True):
- """Return WinPython Start menu shortcuts folder"""
- if current:
- # non-admin install - always goes in this user's start menu.
- folder = get_special_folder_path("CSIDL_PROGRAMS")
- else:
- try:
- folder = get_special_folder_path(
- "CSIDL_COMMON_PROGRAMS"
- )
- except OSError:
- # No CSIDL_COMMON_PROGRAMS on this platform
- folder = get_special_folder_path(
- "CSIDL_PROGRAMS"
- )
- # return osp.join(folder, 'WinPython')
- return str(Path(folder) / 'WinPython')
-
-
-
-def create_winpython_start_menu_folder(current=True):
- """Create WinPython Start menu folder -- remove it if it already exists"""
- path = get_winpython_start_menu_folder(current=current)
- if osp.isdir(path):
- try:
- shutil.rmtree(path, onerror=onerror)
- except WindowsError:
- print(
- "Directory %s could not be removed" % path,
- file=sys.stderr,
- )
- else:
- os.mkdir(path)
- return path
-
-
-def create_shortcut(
- path,
- description,
- filename,
- arguments="",
- workdir="",
- iconpath="",
- iconindex=0,
-):
- """Create Windows shortcut (.lnk file)"""
- import pythoncom
- from win32com.shell import shell
-
- ilink = pythoncom.CoCreateInstance(
- shell.CLSID_ShellLink,
- None,
- pythoncom.CLSCTX_INPROC_SERVER,
- shell.IID_IShellLink,
- )
- ilink.SetPath(path)
- ilink.SetDescription(description)
- if arguments:
- ilink.SetArguments(arguments)
- if workdir:
- ilink.SetWorkingDirectory(workdir)
- if iconpath or iconindex:
- ilink.SetIconLocation(iconpath, iconindex)
- # now save it.
- ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile)
- if not filename.endswith('.lnk'):
- filename += '.lnk'
- ipf.Save(filename, 0)
-
-
-# =============================================================================
-# Misc.
-# =============================================================================
-
-
-def print_box(text):
- """Print text in a box"""
- line0 = "+" + ("-" * (len(text) + 2)) + "+"
- line1 = "| " + text + " |"
- print(
- ("\n\n" + "\n".join([line0, line1, line0]) + "\n")
- )
-
-
-def is_python_distribution(path):
- """Return True if path is a Python distribution"""
- # XXX: This test could be improved but it seems to be sufficient
- has_exec = osp.isfile(get_python_executable(path))
- has_site = osp.isdir(get_site_packages_path(path))
- return has_exec and has_site
-
-
-# =============================================================================
-# Shell, Python queries
-# =============================================================================
-
-
-def decode_fs_string(string):
- """Convert string from file system charset to unicode"""
- charset = sys.getfilesystemencoding()
- if charset is None:
- charset = locale.getpreferredencoding()
- return string.decode(charset)
-
-
-def exec_shell_cmd(args, path):
- """Execute shell command (*args* is a list of arguments) in *path*"""
- # print " ".join(args)
- process = subprocess.Popen(
- args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- cwd=path,
- shell=True,
- )
- return decode_fs_string(process.stdout.read())
-
-def exec_run_cmd(args, path=None):
- """run a single command (*args* is a list of arguments) in optional *path*"""
- # only applicable to Python-3.5+
- # python-3.7+ allows to replace "stdout and stderr ", per "capture_output=True"
- if path:
- process = subprocess.run(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- cwd=path)
- else:
- process = subprocess.run(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- return decode_fs_string(process.stdout)
-
-
-def get_r_version(path):
- """Return version of the R installed in *path*"""
- return (
- exec_shell_cmd('dir ..\README.R*', path)
- .splitlines()[-3]
- .split("-")[-1]
- )
-
-
-def get_julia_version(path):
- """Return version of the Julia installed in *path*"""
- return (
- exec_shell_cmd('julia.exe -v', path)
- .splitlines()[0]
- .split(" ")[-1]
- )
-
-
-def get_nodejs_version(path):
- """Return version of the Nodejs installed in *path*"""
- return exec_shell_cmd('node -v', path).splitlines()[0]
-
-
-def get_npmjs_version(path):
- """Return version of the Nodejs installed in *path*"""
- return exec_shell_cmd('npm -v', path).splitlines()[0]
-
-
-def get_pandoc_version(path):
- """Return version of the Pandoc executable in *path*"""
- return (
- exec_shell_cmd('pandoc -v', path)
- .splitlines()[0]
- .split(" ")[-1]
- )
-
-
-def python_query(cmd, path):
- """Execute Python command using the Python interpreter located in *path*"""
- the_exe = get_python_executable(path)
- # debug2021-09-12
- print('"%s" -c "%s"' % (the_exe, cmd), ' * ', path)
- return exec_shell_cmd('"%s" -c "%s"' % (the_exe, cmd), path).splitlines()[0]
-
-def python_execmodule(cmd, path):
- """Execute Python command using the Python interpreter located in *path*"""
- the_exe = get_python_executable(path)
- exec_shell_cmd('%s -m %s' % (the_exe, cmd), path)
-
-
-def get_python_infos(path):
- """Return (version, architecture) for the Python distribution located in
- *path*. The version number is limited to MAJOR.MINOR, the architecture is
- an integer: 32 or 64"""
- is_64 = python_query(
- 'import sys; print(sys.maxsize > 2**32)', path
- )
- arch = {'True': 64, 'False': 32}.get(is_64, None)
- ver = python_query(
- "import sys; print('%d.%d' % (sys.version_info.major, "
- "sys.version_info.minor))",
- path,
- )
- if re.match(r'([0-9]*)\.([0-9]*)', ver) is None:
- ver = None
-
- return ver, arch
-
-
-def get_python_long_version(path):
- """Return long version (X.Y.Z) for the Python distribution located in
- *path*"""
- ver = python_query(
- "import sys; print('%d.%d.%d' % "
- "(sys.version_info.major, sys.version_info.minor,"
- "sys.version_info.micro))",
- path,
- )
- if (
- re.match(r'([0-9]*)\.([0-9]*)\.([0-9]*)', ver)
- is None
- ):
- ver = None
- return ver
-
-
-# =============================================================================
-# Patch chebang line (courtesy of Christoph Gohlke)
-# =============================================================================
-def patch_shebang_line(
- fname, pad=b' ', to_movable=True, targetdir=""
-):
- """Remove absolute path to python.exe in shebang lines, or re-add it"""
-
- import re
- import sys
- import os
-
- target_dir = targetdir # movable option
- if to_movable == False:
- target_dir = os.path.abspath(os.path.dirname(fname))
- target_dir = (
- os.path.abspath(os.path.join(target_dir, r'..'))
- + '\\'
- )
- executable = sys.executable
- if sys.version_info[0] == 2:
- shebang_line = re.compile(
- r"(#!.*pythonw?\.exe)"
- ) # Python2.7
- else:
- shebang_line = re.compile(
- b"(#!.*pythonw?\.exe)"
- ) # Python3+
- if 'pypy3' in sys.executable:
- shebang_line = re.compile(
- b"(#!.*pypy3w?\.exe)"
- ) # Pypy3+
-
- target_dir = target_dir.encode('utf-8')
- with open(fname, 'rb') as fh:
- initial_content = fh.read()
- fh.close
- fh = None
- content = shebang_line.split(
- initial_content, maxsplit=1
- )
- if len(content) != 3:
- return
- exe = os.path.basename(content[1][2:])
- content[1] = (
- b'#!' + target_dir + exe
- ) # + (pad * (len(content[1]) - len(exe) - 2))
- final_content = b''.join(content)
- if initial_content == final_content:
- return
- try:
- with open(fname, 'wb') as fo:
- fo.write(final_content)
- fo.close
- fo = None
- print("patched", fname)
- except Exception:
- print("failed to patch", fname)
-
-
-# =============================================================================
-# Patch shebang line in .py files
-# =============================================================================
-def patch_shebang_line_py(
- fname, to_movable=True, targetdir=""
-):
- """Changes shebang line in '.py' file to relative or absolue path"""
- import fileinput
- import re
- import sys
-
- if sys.version_info[0] == 2:
- # Python 2.x doesn't create .py files for .exe files. So, Moving
- # WinPython doesn't break running executable files.
- return
- if to_movable:
- exec_path = '#!.\python.exe'
- if 'pypy3' in sys.executable: # PyPy !
- exec_path = '#!.\pypy3.exe'
- else:
- exec_path = '#!' + sys.executable
- for line in fileinput.input(fname, inplace=True):
- if re.match('^#\!.*python\.exe$', line) is not None:
- print(exec_path)
- elif re.match('^#\!.*pypy3\.exe$', line) is not None:# PyPy !
- print(exec_path)
- else:
- print(line, end='')
-
-
-# =============================================================================
-# Guess encoding (shall rather be utf-8 per default)
-# =============================================================================
-def guess_encoding(csv_file):
- """guess the encoding of the given file"""
- # UTF_8_BOM = "\xEF\xBB\xBF"
- # Python behavior on UTF-16 not great on write, so we drop it
- with io.open(csv_file, "rb") as f:
- data = f.read(5)
- if data.startswith(b"\xEF\xBB\xBF"): # UTF-8 with a "BOM" (normally no BOM in utf-8)
- return ["utf-8-sig"]
- else: # in Windows, guessing utf-8 doesn't work, so we have to try
- try:
- with io.open(csv_file, encoding="utf-8") as f:
- preview = f.read(222222)
- return ["utf-8"]
- except:
- return [locale.getdefaultlocale()[1], "utf-8"]
-
-# =============================================================================
-# Patch sourcefile (instead of forking packages)
-# =============================================================================
-def patch_sourcefile(
- fname, in_text, out_text, silent_mode=False
-):
- """Replace a string in a source file"""
- import io
-
- if osp.isfile(fname) and not in_text == out_text:
- the_encoding = guess_encoding(fname)[0]
- with io.open(fname, 'r', encoding=the_encoding) as fh:
- content = fh.read()
- new_content = content.replace(in_text, out_text)
- if not new_content == content:
- if not silent_mode:
- print(
- "patching ",
- fname,
- "from",
- in_text,
- "to",
- out_text,
- )
- with io.open(fname, 'wt', encoding=the_encoding) as fh:
- fh.write(new_content)
-
-
-# =============================================================================
-# Patch sourcelines (instead of forking packages)
-# =============================================================================
-def patch_sourcelines(
- fname,
- in_line_start,
- out_line,
- endline='\n',
- silent_mode=False,
-):
- """Replace the middle of lines between in_line_start and endline """
- import io
- import os.path as osp
-
- if osp.isfile(fname):
- the_encoding = guess_encoding(fname)[0]
- with io.open(fname, 'r', encoding=the_encoding) as fh:
- contents = fh.readlines()
- content = "".join(contents)
- for l in range(len(contents)):
- if contents[l].startswith(in_line_start):
- begining, middle = (
- in_line_start,
- contents[l][len(in_line_start) :],
- )
- ending = ""
- if middle.find(endline) > 0:
- ending = endline + endline.join(
- middle.split(endline)[1:]
- )
- middle = middle.split(endline)[0]
- middle = out_line
- new_line = begining + middle + ending
- if not new_line == contents[l]:
- if not silent_mode:
- print(
- "patching ",
- fname,
- " from\n",
- contents[l],
- "\nto\n",
- new_line,
- )
- contents[l] = new_line
- new_content = "".join(contents)
- if not new_content == content:
- # if not silent_mode:
- # print("patching ", fname, "from", content, "to", new_content)
- with io.open(fname, 'wt', encoding=the_encoding) as fh:
- try:
- fh.write(new_content)
- except:
- print(
- "impossible to patch",
- fname,
- "from",
- content,
- "to",
- new_content,
- )
-
-
-# =============================================================================
-# Extract functions
-# =============================================================================
-def _create_temp_dir():
- """Create a temporary directory and remove it at exit"""
- tmpdir = tempfile.mkdtemp(prefix='wppm_')
- atexit.register(
- lambda path: shutil.rmtree(path, onerror=onerror),
- tmpdir,
- )
- return tmpdir
-
-
-def extract_exe(fname, targetdir=None, verbose=False):
- """Extract .exe archive to a temporary directory (if targetdir
- is None). Return the temporary directory path"""
- if targetdir is None:
- targetdir = _create_temp_dir()
- extract = '7z.exe'
- assert is_program_installed(extract), (
- "Required program '%s' was not found" % extract
- )
- bname = osp.basename(fname)
- args = ['x', '-o%s' % targetdir, '-aos', bname]
- if verbose:
- retcode = subprocess.call(
- [extract] + args, cwd=osp.dirname(fname)
- )
- else:
- p = subprocess.Popen(
- [extract] + args,
- cwd=osp.dirname(fname),
- stdout=subprocess.PIPE,
- )
- p.communicate()
- p.stdout.close()
- retcode = p.returncode
- if retcode != 0:
- raise RuntimeError(
- "Failed to extract %s (return code: %d)"
- % (fname, retcode)
- )
- return targetdir
-
-
-def extract_archive(fname, targetdir=None, verbose=False):
- """Extract .zip, .exe (considered to be a zip archive) or .tar.gz archive
- to a temporary directory (if targetdir is None).
- Return the temporary directory path"""
- if targetdir is None:
- targetdir = _create_temp_dir()
- else:
- try:
- os.mkdir(targetdir)
- except:
- pass
- if osp.splitext(fname)[1] in ('.zip', '.exe'):
- obj = zipfile.ZipFile(fname, mode="r")
- elif fname.endswith('.tar.gz'):
- obj = tarfile.open(fname, mode='r:gz')
- else:
- raise RuntimeError(
- "Unsupported archive filename %s" % fname
- )
- obj.extractall(path=targetdir)
- return targetdir
-
-
-WININST_PATTERN = r'([a-zA-Z0-9\-\_]*|[a-zA-Z\-\_\.]*)-([0-9\.\-]*[a-z]*[0-9]?)(-Qt-([0-9\.]+))?.(win32|win\-amd64)(-py([0-9\.]+))?(-setup)?\.exe'
-
-# SOURCE_PATTERN defines what an acceptable source package name is
-# As of 2014-09-08 :
-# - the wheel package format is accepte in source directory
-# - the tricky regexp is tuned also to support the odd jolib naming :
-# . joblib-0.8.3_r1-py2.py3-none-any.whl,
-# . joblib-0.8.3-r1.tar.gz
-
-SOURCE_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z]*[\-]?[0-9]*)(\.zip|\.tar\.gz|\-(py[2-7]*|py[2-7]*\.py[2-7]*)\-none\-any\.whl)'
-
-# WHEELBIN_PATTERN defines what an acceptable binary wheel package is
-# "cp([0-9]*)" to replace per cp(34) for python3.4
-# "win32|win\_amd64" to replace per "win\_amd64" for 64bit
-WHEELBIN_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z0-9\+]*[0-9]?)-cp([0-9]*)\-[0-9|c|o|n|e|p|m]*\-(win32|win\_amd64)\.whl'
-
-
-def get_source_package_infos(fname):
- """Return a tuple (name, version) of the Python source package"""
- if fname[-4:] == '.whl':
- return osp.basename(fname).split("-")[:2]
- match = re.match(SOURCE_PATTERN, osp.basename(fname))
- if match is not None:
- return match.groups()[:2]
-
-
-def build_wininst(
- root,
- python_exe=None,
- copy_to=None,
- architecture=None,
- verbose=False,
- installer='bdist_wininst',
-):
- """Build wininst installer from Python package located in *root*
- and eventually copy it to *copy_to* folder.
- Return wininst installer full path."""
- if python_exe is None:
- python_exe = sys.executable
- assert osp.isfile(python_exe)
- cmd = [python_exe, 'setup.py', 'build']
- if architecture is not None:
- archstr = (
- 'win32' if architecture == 32 else 'win-amd64'
- )
- cmd += ['--plat-name=%s' % archstr]
- cmd += [installer]
- # root = a tmp dir in windows\tmp,
- if verbose:
- subprocess.call(cmd, cwd=root)
- else:
- p = subprocess.Popen(
- cmd,
- cwd=root,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
- p.communicate()
- p.stdout.close()
- p.stderr.close()
- # distdir = osp.join(root, 'dist')
- distdir = str(Path(root) / 'dist')
- if not osp.isdir(distdir):
- raise RuntimeError(
- "Build failed: see package README file for further"
- " details regarding installation requirements.\n\n"
- "For more concrete debugging infos, please try to build "
- "the package from the command line:\n"
- "1. Open a WinPython command prompt\n"
- "2. Change working directory to the appropriate folder\n"
- "3. Type `python setup.py build install`"
- )
- pattern = WININST_PATTERN.replace(
- r'(win32|win\-amd64)', archstr
- )
- for distname in os.listdir(distdir):
- match = re.match(pattern, distname)
- if match is not None:
- break
- # for wheels (winpython here)
- match = re.match(SOURCE_PATTERN, distname)
- if match is not None:
- break
- match = re.match(WHEELBIN_PATTERN, distname)
- if match is not None:
- break
- else:
- raise RuntimeError(
- "Build failed: not a pure Python package? %s"
- % distdir
- )
- # src_fname = osp.join(distdir, distname)
- src_fname = str(Path(distdir) / distname)
- if copy_to is None:
- return src_fname
- else:
- # dst_fname = osp.join(copy_to, distname)
- dst_fname = str(Path(copy_to) / distname)
- shutil.move(src_fname, dst_fname)
- if verbose:
- print(
- (
- "Move: %s --> %s"
- % (src_fname, (dst_fname))
- )
- )
- # remove tempo dir 'root' no more needed
- shutil.rmtree(root, onerror=onerror)
- return dst_fname
-
-
-def direct_pip_install(
- fname,
- python_exe=None,
- architecture=None,
- verbose=False,
- install_options=None,
-):
- """Direct install via pip !"""
- copy_to = osp.dirname(fname)
-
- if python_exe is None:
- python_exe = sys.executable
- assert osp.isfile(python_exe)
- myroot = os.path.dirname(python_exe)
-
- cmd = [python_exe, '-m', 'pip', 'install']
- if install_options:
- cmd += install_options # typically ['--no-deps']
- print('pip install_options', install_options)
- cmd += [fname]
-
- if verbose:
- subprocess.call(cmd, cwd=myroot)
- else:
- p = subprocess.Popen(
- cmd,
- cwd=myroot,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
- stdout, stderr = p.communicate()
- the_log = "%s" % stdout + "\n %s" % stderr
-
- if (
- ' not find ' in the_log
- or ' not found ' in the_log
- ):
- print("Failed to Install: \n %s \n" % fname)
- print("msg: %s" % the_log)
- raise RuntimeError
- p.stdout.close()
- p.stderr.close()
- src_fname = fname
- if copy_to is None:
- return src_fname
- else:
- if verbose:
- print("Installed %s" % src_fname)
- return src_fname
-
-
-def do_script(
- this_script,
- python_exe=None,
- copy_to=None,
- architecture=None,
- verbose=False,
- install_options=None,
-):
- """Execute a script (get-pip typically)"""
- if python_exe is None:
- python_exe = sys.executable
- myroot = os.path.dirname(python_exe)
-
- # cmd = [python_exe, myroot + r'\Scripts\pip-script.py', 'install']
- cmd = [python_exe]
- if install_options:
- cmd += install_options # typically ['--no-deps']
- print('script install_options', install_options)
- if this_script:
- cmd += [this_script]
- # print('build_wheel', myroot, cmd)
- print("Executing ", cmd)
-
- if verbose:
- subprocess.call(cmd, cwd=myroot)
- else:
- p = subprocess.Popen(
- cmd,
- cwd=myroot,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
- p.communicate()
- p.stdout.close()
- p.stderr.close()
- if verbose:
- print("Executed " % cmd)
- return 'ok'
-
-
-if __name__ == '__main__':
-
- print_box("Test")
- dname = sys.prefix
- print((dname + ':', '\n', get_python_infos(dname)))
- # dname = r'E:\winpython\sandbox\python-2.7.3'
- # print dname+':', '\n', get_python_infos(dname)
-
- tmpdir = r'D:\Tests\winpython_tests'
- if not osp.isdir(tmpdir):
- os.mkdir(tmpdir)
- print(
- (
- extract_archive(
- #osp.join(
- # r'D:\WinP\bd37',
- # 'packages.win-amd64',
- # 'python-3.7.3.amd64.zip',
- #),
- str(Path(r'D:\WinP\bd37') / 'packages.win-amd64' /
- 'python-3.7.3.amd64.zip'),
- tmpdir,
- )
- )
- )
diff --git a/winpython/wppm.py b/winpython/wppm.py
deleted file mode 100644
index 7d56c0af..00000000
--- a/winpython/wppm.py
+++ /dev/null
@@ -1,1030 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2012 Pierre Raybaut
-# Licensed under the terms of the MIT License
-# (see winpython/__init__.py for details)
-
-"""
-WinPython Package Manager
-
-Created on Fri Aug 03 14:32:26 2012
-"""
-# pypy3 to patch from 'python' to 'pypy3': 379 493 497 627 692 696 743 767 785
-from __future__ import print_function
-
-import os
-import os.path as osp
-from pathlib import Path
-import shutil
-import re
-import sys
-import subprocess
-
-# Local imports
-from winpython import utils
-from winpython.config import DATA_PATH
-from winpython.py3compat import configparser as cp
-
-# from former wppm separate script launcher
-import textwrap
-from argparse import ArgumentParser, HelpFormatter, RawTextHelpFormatter
-from winpython import py3compat
-
-from winpython import piptree
-
-# import information reader
-# importlib_metadata before Python 3.8
-try:
- from importlib import metadata as metadata # Python-3.8
- metadata = metadata.metadata
-except:
- try:
- from importlib_metadata import metadata # tuple[list[any], ...]:
+ """Register in Windows (like regedit)"""
+
+ # --- Constants ---
+ DROP_HANDLER_CLSID = "{60254CA5-953B-11CF-8C96-00AA00B8708C}"
+
+ # --- CONFIG ---
+ target_path = Path(target).resolve()
+ python_exe = str(target_path / "python.exe")
+ pythonw_exe = str(target_path / "pythonw.exe")
+ spyder_exe = str(target_path.parent / "Spyder.exe")
+ icon_py = str(target_path / "DLLs" / "py.ico")
+ icon_pyc = str(target_path / "DLLs" / "pyc.ico")
+ idle_path = str(target_path / "Lib" / "idlelib" / "idle.pyw")
+ doc_path = str(target_path / "Doc" / "html" / "index.html")
+ python_infos = utils.get_python_infos(target) # ('3.11', 64)
+ short_version = python_infos[0] # e.g., '3.11'
+ version = utils.get_python_long_version(target) # e.g., '3.11.5'
+ arch = f'{python_infos[1]}bit' # e.g., '64bit'
+ display = f"Python {version} ({arch})"
+
+ permanent_entries = [] # key_path, name, value
+ dynamic_entries = [] # key_path, name, value
+ core_entries = [] # key_path, name, value
+ lost_entries = [] # intermediate keys to remove later
+ # --- File associations ---
+ ext_map = {".py": "Python.File", ".pyw": "Python.NoConFile", ".pyc": "Python.CompiledFile"}
+ ext_label = {".py": "Python File", ".pyw": "Python File (no console)", ".pyc": "Compiled Python File"}
+ for ext, ftype in ext_map.items():
+ permanent_entries.append((f"Software\\Classes\\{ext}", None, ftype))
+ if ext in (".py", ".pyw"):
+ permanent_entries.append((f"Software\\Classes\\{ext}", "Content Type", "text/plain"))
+
+ # --- Descriptions, Icons, DropHandlers ---
+ for ext, ftype in ext_map.items():
+ dynamic_entries.append((f"Software\\Classes\\{ftype}", None, ext_label[ext]))
+ dynamic_entries.append((f"Software\\Classes\\{ftype}\\DefaultIcon", None, icon_py if "Compiled" not in ftype else icon_pyc))
+ dynamic_entries.append((f"Software\\Classes\\{ftype}\\shellex\\DropHandler", None, DROP_HANDLER_CLSID))
+ lost_entries.append((f"Software\\Classes\\{ftype}\\shellex", None, None))
+
+ # --- Shell commands ---
+ for ext, ftype in ext_map.items():
+ dynamic_entries.append((f"Software\\Classes\\{ftype}\\shell\\open\\command", None, f'''"{pythonw_exe if ftype=='Python.NoConFile' else python_exe}" "%1" %*'''))
+ lost_entries.append((f"Software\\Classes\\{ftype}\\shell\\open", None, None))
+ lost_entries.append((f"Software\\Classes\\{ftype}\\shell", None, None))
+
+ dynamic_entries.append((rf"Software\Classes\Python.File\shell\Edit with IDLE\command", None, f'"{pythonw_exe}" "{idle_path}" -n -e "%1"'))
+ dynamic_entries.append((rf"Software\Classes\Python.NoConFile\shell\Edit with IDLE\command", None, f'"{pythonw_exe}" "{idle_path}" -n -e "%1"'))
+ lost_entries.append((rf"Software\Classes\Python.File\shell\Edit with IDLE", None, None))
+ lost_entries.append((rf"Software\Classes\Python.NoConFile\shell\Edit with IDLE", None, None))
+
+ if Path(spyder_exe).exists():
+ dynamic_entries.append((rf"Software\Classes\Python.File\shell\Edit with Spyder\command", None, f'"{spyder_exe}" "%1" -w "%w"'))
+ dynamic_entries.append((rf"Software\Classes\Python.NoConFile\shell\Edit with Spyder\command", None, f'"{spyder_exe}" "%1" -w "%w"'))
+ lost_entries.append((rf"Software\Classes\Python.File\shell\Edit with Spyder", None, None))
+ lost_entries.append((rf"Software\Classes\Python.NoConFile\shell\Edit with Spyder", None, None))
+
+ # --- WinPython Core registry entries (PEP 514 style) ---
+ base = f"Software\\Python\\WinPython\\{short_version}"
+ core_entries.append((base, "DisplayName", display))
+ core_entries.append((base, "SupportUrl", "https://winpython.github.io"))
+ core_entries.append((base, "SysVersion", short_version))
+ core_entries.append((base, "SysArchitecture", arch))
+ core_entries.append((base, "Version", version))
+
+ core_entries.append((f"{base}\\InstallPath", None, str(target)))
+ core_entries.append((f"{base}\\InstallPath", "ExecutablePath", python_exe))
+ core_entries.append((f"{base}\\InstallPath", "WindowedExecutablePath", pythonw_exe))
+ core_entries.append((f"{base}\\InstallPath\\InstallGroup", None, f"Python {short_version}"))
+
+ core_entries.append((f"{base}\\Modules", None, ""))
+ core_entries.append((f"{base}\\PythonPath", None, f"{target}\\Lib;{target}\\DLLs"))
+ core_entries.append((f"{base}\\Help\\Main Python Documentation", None, doc_path))
+ lost_entries.append((f"{base}\\Help", None, None))
+ lost_entries.append((f"Software\\Python\\WinPython", None, None))
+
+ return permanent_entries, dynamic_entries, core_entries, lost_entries
+
+# --- Main Register/Unregister Functions ---
+
+def register(target, current=True, reg_type=winreg.REG_SZ, verbose=True):
+ """Register a Python distribution in Windows registry and create Start Menu shortcuts"""
+ root = winreg.HKEY_CURRENT_USER if current else winreg.HKEY_LOCAL_MACHINE
+ has_pywin32 = _has_pywin32()
+
+ if verbose:
+ print(f'Creating WinPython registry entries for {target}')
+
+ permanent_entries, dynamic_entries, core_entries, lost_entries = register_in_registery(target)
+ # Set registry entries for given target
+ for key_path, name, value in permanent_entries + dynamic_entries + core_entries:
+ _set_reg_value(root, key_path, name, value, verbose=verbose)
+
+ # Create start menu entries
+ if has_pywin32:
+ if verbose:
+ print(f'Creating WinPython menu for all icons in {Path(target).parent}')
+ for path, desc, fname in _get_shortcut_data(target, current=current, has_pywin32=True):
+ try:
+ create_shortcut(path, desc, fname, verbose=verbose)
+ except Exception as e:
+ print(f"Error creating shortcut for {desc} at {fname}: {e}", file=sys.stderr)
+ else:
+ print("Skipping start menu shortcut creation as pywin32 package is needed.")
+
+def unregister(target, current=True, verbose=True):
+ """Unregister a Python distribution from Windows registry and remove Start Menu shortcuts"""
+ root = winreg.HKEY_CURRENT_USER if current else winreg.HKEY_LOCAL_MACHINE
+ has_pywin32 = _has_pywin32()
+
+ if verbose:
+ print(f'Removing WinPython registry entries for {target}')
+
+ permanent_entries, dynamic_entries, core_entries , lost_entries = register_in_registery(target)
+
+ # List of keys to attempt to delete, ordered from most specific to general
+ keys_to_delete = sorted(list(set(key_path for key_path , name, value in (dynamic_entries + core_entries + lost_entries))), key=len, reverse=True)
+
+ rootkey_name = "HKEY_CURRENT_USER" if root == winreg.HKEY_CURRENT_USER else "HKEY_LOCAL_MACHINE"
+ for key_path in keys_to_delete:
+ _delete_reg_key(root, key_path, verbose=verbose)
+
+ # Remove start menu shortcuts
+ if has_pywin32:
+ if verbose:
+ print(f'Removing WinPython menu for all icons in {Path(target).parent}')
+ _remove_start_menu_folder(target, current=current, has_pywin32=True)
+ # The original code had commented out code to delete .lnk files individually.
+ else:
+ print("Skipping start menu removal as pywin32 package is needed.")
+
+
+if __name__ == "__main__":
+ # Ensure we are running from the target WinPython environment
+ parser = ArgumentParser(description="Register or Un-register Python file extensions, icons "\
+ "and Windows explorer context menu to this "\
+ "Python distribution.")
+ parser.add_argument('--unregister', action="store_true",
+ help='register to all users, requiring administrative '\
+ 'privileges (default: register to current user only)')
+ parser.add_argument('--all', action="store_true",
+ help='action is to all users, requiring administrative '\
+ 'privileges (default: to current user only)')
+ args = parser.parse_args()
+ expected_target = Path(sys.prefix)
+ command = "unregister" if args.unregister else "register"
+ users = "all" if args.all else "user"
+ print(f"Attempting to {command} the Python environment for {users} at: {expected_target}")
+
+ target_dir = sys.prefix # Or get from arguments
+ is_current_user = True # Or get from arguments
+ if command == "register":
+ register(expected_target, current=not args.all)
+ else:
+ unregister(expected_target, current=not args.all)
diff --git a/wppm/diff.py b/wppm/diff.py
new file mode 100644
index 00000000..5e1de9b2
--- /dev/null
+++ b/wppm/diff.py
@@ -0,0 +1,211 @@
+# -*- coding: utf-8 -*-
+#
+# WinPython diff.py script (streamlined, with historical and flexible modes)
+# Copyright © 2013 Pierre Raybaut
+# Copyright © 2014-2025+ The Winpython development team https://github.com/winpython/
+# Licensed under the terms of the MIT License
+
+import os
+import re
+import sys
+import shutil
+from pathlib import Path
+from packaging import version
+from . import utils
+
+CHANGELOGS_DIR = Path(__file__).parent.parent / "changelogs"
+
+class Package:
+ PATTERNS = [
+ r"\[([\w\-\:\/\.\_]+)\]\(([^)]+)\) \| ([^\|]*) \| ([^\|]*)", # SourceForge
+ r"\[([\w\-\:\/\.\_]+) ([^\]\ ]+)\] \| ([^\|]*) \| ([^\|]*)" # Google Code
+ ]
+ def __init__(self, text=None):
+ self.name = self.url = self.version = self.description = None
+ if text:
+ self.from_text(text)
+ def from_text(self, text):
+ for pattern in self.PATTERNS:
+ match = re.match(pattern, text)
+ if match:
+ self.name, self.url, self.version, self.description = match.groups()
+ return
+ raise ValueError(f"Unrecognized package line format: {text}")
+
+class PackageIndex:
+ HEADERS = {"tools": "### Tools", "python": "### Python packages", "wheelhouse": "### WheelHouse packages"}
+ BLANKS = ["Name | Version | Description", "-----|---------|------------", "", "", " "]
+
+ def __init__(self, content):
+ self.packages = {k: {} for k in self.HEADERS}
+ self._parse_index(content)
+
+ def _parse_index(self, text):
+ current = None
+ for line in text.splitlines():
+ if line in self.HEADERS.values():
+ current = [k for k, v in self.HEADERS.items() if v == line][0]
+ continue
+ if line.strip() in self.BLANKS:
+ continue
+ if current:
+ try:
+ pkg = Package(line)
+ self.packages[current][pkg.name] = pkg
+ except Exception:
+ continue
+
+def compare_packages(old, new):
+ def normalize(d): return {k.replace("-", "_").lower(): v for k, v in d.items()}
+ old, new = normalize(old), normalize(new)
+ added = [new[k] for k in new if k not in old]
+ upgraded = [new[k] for k in new if k in old and new[k].version != old[k].version]
+ removed = [old[k] for k in old if k not in new]
+ output = ""
+ if added:
+ output += "\nNew packages:\n" + "".join(f" * {p.name} {p.version} ({p.description})\n" for p in added)
+ if upgraded:
+ output += "\nUpgraded packages:\n" + "".join(f" * {p.name} {old[p.name].version} → {p.version} ({p.description})\n" for p in upgraded if p.name in old)
+ if removed:
+ output += "\nRemoved packages:\n" + "".join(f" * {p.name} {p.version} ({p.description})\n" for p in removed)
+ return output or "\nNo differences found.\n"
+
+def compare_markdown_sections(md1, md2, header1="python", header2="python", label1="Input1", label2="Input2"):
+ pkgs1 = PackageIndex(md1).packages
+ pkgs2 = PackageIndex(md2).packages
+ diff = compare_packages(pkgs1[header1], pkgs2[header2])
+ # If comparing the same section, use the historical header
+ if header1 == header2 and header1 in PackageIndex.HEADERS:
+ title = PackageIndex.HEADERS[header1]
+ else:
+ title = f"## {label1} [{header1}] vs {label2} [{header2}]"
+ return f"{title}\n\n{diff}"
+
+def compare_markdown_section_pairs(md1, md2, header_pairs, label1="Input1", label2="Input2"):
+ pkgs1 = PackageIndex(md1).packages
+ pkgs2 = PackageIndex(md2).packages
+ text = f"# {label1} vs {label2} section-pairs comparison\n"
+ for h1, h2 in header_pairs:
+ diff = compare_packages(pkgs1[h1], pkgs2[h2])
+ if diff.strip() and diff != "No differences found.\n":
+ text += f"\n## {label1} [{h1}] vs {label2} [{h2}]\n\n{diff}\n"
+ return text
+
+def compare_files(file1, file2, mode="full", header1=None, header2=None, header_pairs=None):
+ with open(file1, encoding=utils.guess_encoding(file1)[0]) as f1, \
+ open(file2, encoding=utils.guess_encoding(file2)[0]) as f2:
+ md1, md2 = f1.read(), f2.read()
+ if mode == "full":
+ result = ""
+ for k in PackageIndex.HEADERS:
+ result += compare_markdown_sections(md1, md2, k, k, file1, file2) + "\n"
+ return result
+ elif mode == "section":
+ return compare_markdown_sections(md1, md2, header1, header2, file1, file2)
+ elif mode == "pairs":
+ return compare_markdown_section_pairs(md1, md2, header_pairs, file1, file2)
+ else:
+ raise ValueError("Unknown mode.")
+
+# --- ORIGINAL/HISTORICAL VERSION-TO-VERSION COMPARISON ---
+
+def find_previous_version(target_version, searchdir=None, flavor="", architecture=64):
+ search_dir = Path(searchdir) if searchdir else CHANGELOGS_DIR
+ pattern = re.compile(rf"WinPython{flavor}-{architecture}bit-([0-9\.]+)\.(txt|md)")
+ versions = [pattern.match(f).group(1) for f in os.listdir(search_dir) if pattern.match(f)]
+ versions = [v for v in versions if version.parse(v) < version.parse(target_version)]
+ return max(versions, key=version.parse, default=target_version)
+
+def load_version_markdown(version, searchdir, flavor="", architecture=64):
+ filename = Path(searchdir) / f"WinPython{flavor}-{architecture}bit-{version}.md"
+ if not filename.exists():
+ raise FileNotFoundError(f"Changelog not found: {filename}")
+ with open(filename, "r", encoding=utils.guess_encoding(filename)[0]) as f:
+ return f.read()
+
+def compare_package_indexes(version2, version1=None, searchdir=None, flavor="", flavor1=None, architecture=64):
+ searchdir = Path(searchdir) if searchdir else CHANGELOGS_DIR
+ version1 = version1 or find_previous_version(version2, searchdir, flavor, architecture)
+ flavor1 = flavor1 or flavor
+ md1 = load_version_markdown(version1, searchdir, flavor1, architecture)
+ md2 = load_version_markdown(version2, searchdir, flavor, architecture)
+ result = f"# WinPython {architecture}bit {version2}{flavor} vs {version1}{flavor1}\n"
+ result = (
+ f"## History of changes for WinPython-{architecture}bit {version2 + flavor}\r\n\r\n"
+ f"The following changes were made to WinPython-{architecture}bit distribution since version {version1 + flavor1}.\n\n\n"
+ "\n"
+ )
+ for k in PackageIndex.HEADERS:
+ result += compare_markdown_sections(md1, md2, k, k, version1, version2) + "\n"
+ return result+ "\n\n* * *\n"
+
+def copy_changelogs(version, searchdir, flavor="", architecture=64, basedir=None):
+ """Copy all changelogs for a major.minor version into basedir."""
+ basever = ".".join(str(version).split(".")[:2])
+ pattern = re.compile(rf"WinPython{flavor}-{architecture}bit-{basever}[0-9\.]*\.(txt|md)")
+ dest = Path(basedir)
+ for fname in os.listdir(searchdir):
+ if pattern.match(fname):
+ shutil.copyfile(Path(searchdir) / fname, dest / fname)
+
+def write_changelog(version2, version1=None, searchdir=None, flavor="", architecture=64, basedir=None):
+ """Write changelog between version1 and version2 of WinPython."""
+ searchdir = Path(searchdir) if searchdir else CHANGELOGS_DIR
+ if basedir:
+ copy_changelogs(version2, searchdir, flavor, architecture, basedir)
+ changelog = compare_package_indexes(version2, version1, searchdir, flavor, architecture=architecture)
+ output_file = searchdir / f"WinPython{flavor}-{architecture}bit-{version2}_History.md"
+ with open(output_file, "w", encoding="utf-8") as f:
+ f.write(changelog)
+ if basedir:
+ shutil.copyfile(output_file, Path(basedir) / output_file.name)
+
+def print_usage():
+ print("Usage:")
+ print(" python diff.py file1.md file2.md")
+ print(" - Compare all sections of two markdown files.")
+ print(" python diff.py file1.md file2.md --section header1 header2")
+ print(" - Compare section 'header1' of file1 with section 'header2' of file2.")
+ print(" python diff.py file1.md file2.md --pairs header1a header2a [header1b header2b ...]")
+ print(" - Compare pairs of sections. Example: python diff.py f1.md f2.md --pairs python wheelhouse tools tools")
+ print(" python diff.py [searchdir] [flavor] [architecture]")
+ print(" - Compare WinPython markdown changelogs by version (historical mode).")
+ print(" python diff.py --write-changelog [searchdir] [flavor] [architecture] [basedir]")
+ print(" - Write changelog between version1 and version2 to file (and optionally copy to basedir).")
+
+if __name__ == "__main__":
+ args = sys.argv
+ if len(args) >= 3 and all(arg.lower().endswith('.md') for arg in args[1:3]):
+ file1, file2 = args[1], args[2]
+ if len(args) == 3:
+ print(compare_files(file1, file2))
+ elif args[3] == "--section" and len(args) >= 6:
+ h1, h2 = args[4], args[5]
+ print(compare_files(file1, file2, mode="section", header1=h1, header2=h2))
+ elif args[3] == "--pairs" and len(args) > 4 and len(args[4:]) % 2 == 0:
+ pairs = list(zip(args[4::2], args[5::2]))
+ print(compare_files(file1, file2, mode="pairs", header_pairs=pairs))
+ else:
+ print_usage()
+ elif len(args) >= 2 and args[1] == "--write-changelog":
+ # Usage: --write-changelog [searchdir] [flavor] [architecture] [basedir]
+ if len(args) < 4:
+ print_usage()
+ sys.exit(1)
+ version2 = args[2]
+ version1 = args[3]
+ searchdir = args[4] if len(args) > 4 else CHANGELOGS_DIR
+ flavor = args[5] if len(args) > 5 else ""
+ architecture = int(args[6]) if len(args) > 6 else 64
+ basedir = args[7] if len(args) > 7 else None
+ write_changelog(version2, version1, searchdir, flavor, architecture, basedir)
+ print(f"Changelog written for {version2} vs {version1}.")
+ elif len(args) >= 3:
+ version2 = args[1]
+ version1 = args[2] if len(args) > 2 and not args[2].endswith('.md') else None
+ searchdir = args[3] if len(args) > 3 else CHANGELOGS_DIR
+ flavor = args[4] if len(args) > 4 else ""
+ architecture = int(args[5]) if len(args) > 5 else 64
+ print(compare_package_indexes(version2, version1, searchdir, flavor, architecture=architecture))
+ else:
+ print_usage()
\ No newline at end of file
diff --git a/wppm/hash.py b/wppm/hash.py
new file mode 100644
index 00000000..e0bdd46a
--- /dev/null
+++ b/wppm/hash.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+"""
+hash.py: compute hash of given files into a markdown output
+"""
+# Copyright © 2014-2025+ The Winpython development team https://github.com/winpython/
+# Licensed under the terms of the MIT License
+# (see winpython/__init__.py for details)
+
+from pathlib import Path
+import sys
+import hashlib
+
+def compute_hash(file_path, hash_function, digest_size=None):
+ """Compute the hash of a file using the specified hash function."""
+ try:
+ with open(file_path, 'rb') as file:
+ if digest_size:
+ return hash_function(file.read(), digest_size=digest_size).hexdigest()
+ return hash_function(file.read()).hexdigest()
+ except IOError as e:
+ print(f"Error reading file {file_path}: {e}")
+ return None
+
+def print_hashes(files):
+ """Print the hashes of the given files."""
+ header = f"{'MD5':<32} | {'SHA-1':<40} | {'SHA-256':<64} | {'Binary':<33} | {'Size':<20} | {'blake2b-256':<64}"
+ line = "|".join(["-" * len(part) for part in header.split("|")])
+
+ print(header)
+ print(line)
+
+ for file in sorted(files):
+ md5 = compute_hash(file, hashlib.md5)
+ sha1 = compute_hash(file, hashlib.sha1)
+ sha256 = compute_hash(file, hashlib.sha256)
+ name = Path(file).name.ljust(33)
+ size = f"{Path(file).stat().st_size:,} Bytes".replace(",", " ").rjust(20)
+ blake2b = compute_hash(file, hashlib.blake2b, digest_size=32)
+ print(f"{md5} | {sha1} | {sha256} | {name} | {size} | {blake2b}")
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print("Usage: hash.py files_to_compute_hash")
+ sys.exit(1)
+ files = [file for file in sys.argv[1:] if file[-3:].lower() != ".py"]
+ print_hashes(files)
diff --git a/wppm/packagemetadata.py b/wppm/packagemetadata.py
new file mode 100644
index 00000000..c82efd91
--- /dev/null
+++ b/wppm/packagemetadata.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+"""
+packagemetadata.py - get metadata from designated place
+"""
+import os
+import re
+import tarfile
+import zipfile
+import sys
+from pathlib import Path
+from typing import Dict, List, Optional, Tuple
+from . import utils
+import importlib.metadata
+import email
+#from packaging.utils import canonicalize_name
+# --- Abstract metadata accessor ---
+
+class PackageMetadata:
+ """A minimal abstraction for package metadata."""
+ def __init__(self, name, version, requires, summary, description, metadata):
+ self.name = name
+ self.version = version
+ self.requires = requires # List[str] of dependencies
+ self.summary = summary
+ self.description = description
+ self.metadata = metadata
+
+def get_installed_metadata(path = None) -> List[PackageMetadata]:
+ # Use importlib.metadata or pkg_resources
+ pkgs = []
+ distro = importlib.metadata.distributions(path = path) if path else importlib.metadata.distributions()
+ for dist in distro:
+ name = utils.canonicalize_name(dist.metadata['Name'])
+ version = dist.version
+ summary = dist.metadata.get("Summary", ""),
+ description = dist.metadata.get("Description", ""),
+ requires = dist.requires or []
+ metadata = dist.metadata
+ pkgs.append(PackageMetadata(name, version, requires, summary, description, metadata))
+ return pkgs
+
+def get_directory_metadata(directory: str) -> List[PackageMetadata]:
+ # For each .whl/.tar.gz file in directory, extract metadata
+ pkgs = []
+ for fname in os.listdir(directory):
+ if fname.endswith('.whl'):
+ # Extract METADATA from wheel
+ meta = extract_metadata_from_wheel(os.path.join(directory, fname))
+ pkgs.append(meta)
+ elif fname.endswith('.tar.gz'):
+ # Extract PKG-INFO from sdist
+ meta = extract_metadata_from_sdist(os.path.join(directory, fname))
+ pkgs.append(meta)
+ return pkgs
+
+def extract_metadata_from_wheel(path: str) -> PackageMetadata:
+ with zipfile.ZipFile(path) as zf:
+ for name in zf.namelist():
+ if name.endswith(r'.dist-info/METADATA') and name.split("/")[1] == "METADATA":
+ with zf.open(name) as f:
+ # Parse metadata (simple parsing for Name, Version, Requires-Dist)
+ return parse_metadata_file(f.read().decode())
+ raise ValueError(f"No METADATA found in {path}")
+
+def extract_metadata_from_sdist(path: str) -> PackageMetadata:
+ with tarfile.open(path, "r:gz") as tf:
+ for member in tf.getmembers():
+ if member.name.endswith('PKG-INFO'):
+ f = tf.extractfile(member)
+ return parse_metadata_file(f.read().decode())
+ raise ValueError(f"No PKG-INFO found in {path}")
+
+def parse_metadata_file(txt: str) -> PackageMetadata:
+ meta = email.message_from_string(txt)
+ name = utils.canonicalize_name(meta.get('Name', ''))
+ version = meta.get('Version', '')
+ summary = meta.get('Summary', '')
+ description = meta.get('Description', '')
+ requires = meta.get_all('Requires-Dist') or []
+ return PackageMetadata(name, version, requires, summary, description, dict(meta.items()))
+
+def main():
+ if len(sys.argv) > 1:
+ # Directory mode
+ directory = sys.argv[1]
+ pkgs = get_directory_metadata(directory)
+ else:
+ # Installed packages mode
+ pkgs = get_installed_metadata()
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/wppm/piptree.py b/wppm/piptree.py
new file mode 100644
index 00000000..d6569b4d
--- /dev/null
+++ b/wppm/piptree.py
@@ -0,0 +1,290 @@
+# -*- coding: utf-8 -*-
+"""
+piptree.py: inspect and display Python package dependencies,
+supporting both downward and upward dependency trees.
+Requires Python 3.8+ due to importlib.metadata.
+"""
+
+import json
+import sys
+import re
+import platform
+import os
+import logging
+from functools import lru_cache
+from collections import OrderedDict
+from typing import Dict, List, Optional, Tuple, Union
+from pip._vendor.packaging.markers import Marker
+from importlib.metadata import Distribution, distributions
+from pathlib import Path
+from . import utils
+from . import packagemetadata as pm
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+class PipDataError(Exception):
+ """Custom exception for PipData related errors."""
+ pass
+
+class PipData:
+ """Manages package metadata and dependency relationships in a Python environment."""
+
+ def __init__(self, target: Optional[str] = None, wheelhouse = None):
+ """
+ Initialize the PipData instance.
+
+ :param target: Optional target path to search for packages
+ """
+ self.distro: Dict[str, Dict] = {}
+ self.raw: Dict[str, Dict] = {}
+ self.environment = self._get_environment()
+ try:
+ packages = self._get_packages(target or sys.executable, wheelhouse)
+ self._process_packages(packages)
+ self._populate_reverse_dependencies()
+ except Exception as e:
+ raise PipDataError(f"Failed to initialize package data: {str(e)}") from e
+
+ @staticmethod
+ @lru_cache(maxsize=None)
+ def normalize(name: str) -> str:
+ """Normalize package name per PEP 503."""
+ return re.sub(r"[-_.]+", "-", name).lower()
+
+ def _get_environment(self) -> Dict[str, str]:
+ """Collect system and Python environment details."""
+ return {
+ "implementation_name": sys.implementation.name,
+ "implementation_version": f"{sys.implementation.version.major}.{sys.implementation.version.minor}.{sys.implementation.version.micro}",
+ "os_name": os.name,
+ "platform_machine": platform.machine(),
+ "platform_release": platform.release(),
+ "platform_system": platform.system(),
+ "platform_version": platform.version(),
+ "python_full_version": platform.python_version(),
+ "platform_python_implementation": platform.python_implementation(),
+ "python_version": ".".join(platform.python_version_tuple()[:2]),
+ "sys_platform": sys.platform,
+ }
+
+ def _get_packages(self, search_path: str, wheelhouse) -> List[Distribution]:
+ """Retrieve installed packages from the specified path."""
+ if wheelhouse:
+ return pm.get_directory_metadata(wheelhouse)
+ if sys.executable == search_path:
+ return pm.get_installed_metadata() #Distribution.discover()
+ else:
+ return pm.get_installed_metadata(path=[str(Path(search_path).parent / 'lib' / 'site-packages')]) #distributions(path=[str(Path(search_path).parent / 'lib' / 'site-packages')])
+
+ def _process_packages(self, packages: List[Distribution]) -> None:
+ """Process packages metadata and store them in the distro dictionary."""
+ for package in packages:
+ try:
+ meta = package.metadata
+ name = meta.get('Name')
+ if not name:
+ continue
+ key = self.normalize(name)
+ self.raw[key] = meta
+ self.distro[key] = {
+ "name": name,
+ "version": package.version,
+ "summary": meta.get("Summary", ""),
+ "requires_dist": self._get_requires(package),
+ "reverse_dependencies": [],
+ "description": meta.get("Description", ""),
+ "provides": self._get_provides(package),
+ "provided": {'': None} # Placeholder for extras provided by this package
+ }
+ except Exception as e:
+ logger.warning(f"Failed to process package {name}: {str(e)}", exc_info=True)
+
+ def _get_requires(self, package: Distribution) -> List[Dict[str, str]]:
+ """Extract and normalize requirements for a package."""
+ requires = []
+ replacements = str.maketrans({" ": " ", "[": "", "]": "", "'": "", '"': ""})
+ further_replacements = [
+ (' == ', '=='), ('= ', '='), (' !=', '!='), (' ~=', '~='),
+ (' <', '<'), ('< ', '<'), (' >', '>'), ('> ', '>'),
+ ('; ', ';'), (' ;', ';'), ('( ', '('),
+ (' and (', ' andZZZZZ('), (' (', '('), (' andZZZZZ(', ' and (')
+ ]
+
+ if package.requires:
+ for req in package.requires:
+ req_nameextra, req_marker = (req + ";").split(";")[:2]
+ req_nameextra = self.normalize(re.split(r" |;|==|!|>|<|~=", req_nameextra + ";")[0])
+ req_key = self.normalize((req_nameextra + "[").split("[")[0])
+ req_key_extra = req_nameextra[len(req_key) + 1:].split("]")[0]
+ req_version = req[len(req_nameextra):].translate(replacements)
+
+ for old, new in further_replacements:
+ req_version = req_version.replace(old, new)
+
+ req_add = {
+ "req_key": req_key,
+ "req_version": req_version,
+ "req_extra": req_key_extra,
+ }
+ if req_marker != "":
+ req_add["req_marker"] = req_marker
+ requires.append(req_add)
+ return requires
+
+ def _get_provides(self, package: Distribution) -> Dict[str, None]:
+ """Extract provided extras from package requirements."""
+ provides = {'': None}
+ if package.requires:
+ for req in package.requires:
+ req_marker = (req + ";").split(";")[1]
+ if 'extra == ' in req_marker:
+ remove_list = {ord("'"): None, ord('"'): None}
+ provides[req_marker.split('extra == ')[1].translate(remove_list)] = None
+ return provides
+
+ def _populate_reverse_dependencies(self) -> None:
+ """Populate reverse dependencies."""
+ for pkg_key, pkg_data in self.distro.items():
+ for req in pkg_data["requires_dist"]:
+ target_key = req["req_key"]
+ if target_key in self.distro:
+ rev_dep = {"req_key": pkg_key, "req_version": req["req_version"], "req_extra": req["req_extra"]}
+ if "req_marker" in req:
+ rev_dep["req_marker"] = req["req_marker"]
+ if 'extra == ' in req["req_marker"]:
+ remove_list = {ord("'"): None, ord('"'): None}
+ self.distro[target_key]["provided"][req["req_marker"].split('extra == ')[1].translate(remove_list)] = None
+ self.distro[target_key]["reverse_dependencies"].append(rev_dep)
+
+ def _get_dependency_tree(self, package_name: str, extra: str = "", version_req: str = "", depth: int = 20, path: Optional[List[str]] = None, verbose: bool = False, upward: bool = False) -> List[List[str]]:
+ """Recursive function to build dependency tree."""
+ path = path or []
+ extras = extra.split(",")
+ pkg_key = self.normalize(package_name)
+ ret_all = []
+
+ full_name = f"{package_name}[{extra}]" if extra else package_name
+ if full_name in path:
+ logger.warning(f"Cycle detected: {' -> '.join(path + [full_name])}")
+ return []
+
+ pkg_data = self.distro[pkg_key]
+ if pkg_data and len(path) <= depth:
+ for extra in extras:
+ environment = {"extra": extra, **self.environment}
+ summary = f' {pkg_data["summary"]}' if verbose else ''
+ base_name = f'{package_name}[{extra}]' if extra else package_name
+ ret = [f'{base_name}=={pkg_data["version"]} {version_req}{summary}']
+
+ dependencies = pkg_data["requires_dist"] if not upward else pkg_data["reverse_dependencies"]
+
+ for dependency in dependencies:
+ if dependency["req_key"] in self.distro:
+ next_path = path + [base_name]
+ if upward:
+ up_req = (dependency.get("req_marker", "").split('extra == ')+[""])[1].strip("'\"")
+ if dependency["req_key"] in self.distro and dependency["req_key"]+"["+up_req+"]" not in path:
+ # upward dependancy taken if:
+ # - if extra "" demanded, and no marker from upward package: like pandas[] ==> numpy
+ # - or the extra is in the upward package, like pandas[test] ==> pytest, for 'test' extra
+ # - or an extra "array" is demanded, and indeed in the req_extra list: array,dataframe,diagnostics,distributer
+ if (not dependency.get("req_marker") and extra == "") or \
+ ("req_marker" in dependency and extra == up_req and \
+ dependency["req_key"] != pkg_key and \
+ Marker(dependency["req_marker"]).evaluate(environment=environment)) or \
+ ("req_marker" in dependency and extra != "" and \
+ extra + ',' in dependency["req_extra"] + ',' and \
+ Marker(dependency["req_marker"]).evaluate(environment=environment | {"extra": up_req})):
+ # IA risk error: # dask[array] go upwards as dask[dataframe], so {"extra": up_req} , not {"extra": extra}
+ #tag downward limiting dependancies
+ wall = " " if dependency["req_version"][:1] == "~" or dependency["req_version"].startswith("==") or "<" in dependency["req_version"] else ""
+ ret += self._get_dependency_tree(
+ dependency["req_key"],
+ up_req,
+ f"[requires{wall}: {package_name}"
+ + (f"[{dependency['req_extra']}]" if dependency["req_extra"] != "" else "")
+ + f'{dependency["req_version"]}]',
+ depth,
+ next_path,
+ verbose=verbose,
+ upward=upward,
+ )
+ elif not dependency.get("req_marker") or Marker(dependency["req_marker"]).evaluate(environment=environment):
+ ret += self._get_dependency_tree(
+ dependency["req_key"],
+ dependency["req_extra"],
+ dependency["req_version"],
+ depth,
+ next_path,
+ verbose=verbose,
+ upward=upward,
+ )
+
+ ret_all.append(ret)
+ return ret_all
+
+ def down(self, pp: str = "", extra: str = "", depth: int = 20, indent: int = 5, version_req: str = "", verbose: bool = False) -> str:
+ """Generate downward dependency tree as formatted string."""
+ if pp == ".":
+ results = [self.down(p, extra, depth, indent, version_req, verbose=verbose) for p in sorted(self.distro)]
+ return '\n'.join(filter(None, results))
+
+ if extra == ".":
+ if pp in self.distro:
+ results = [self.down(pp, one_extra, depth, indent, version_req, verbose=verbose)
+ for one_extra in sorted(self.distro[pp]["provides"])]
+ return '\n'.join(filter(None, results))
+ return ""
+
+ if pp not in self.distro:
+ return ""
+
+ rawtext = json.dumps(self._get_dependency_tree(pp, extra, version_req, depth, verbose=verbose), indent=indent)
+ lines = [l for l in rawtext.split("\n") if len(l.strip()) > 2]
+ return "\n".join(lines).replace('"', "")
+
+ def up(self, ppw: str, extra: str = "", depth: int = 20, indent: int = 5, version_req: str = "", verbose: bool = False) -> str:
+ """Generate upward dependency tree as formatted string."""
+ pp = ppw[:-1] if ppw.endswith('!') else ppw
+ ppend = "!" if ppw.endswith('!') else "" #show only downward limiting dependancies
+ if pp == ".":
+ results = [aa for p in sorted(self.distro) if '[requires' in (aa:=self.up(p + ppend, extra, depth, indent, version_req, verbose))]
+ return '\n'.join(filter(None, results))
+
+ if extra == ".":
+ if pp in self.distro:
+ extras = set(self.distro[pp]["provided"]).union(set(self.distro[pp]["provides"]))
+ results = [self.up(pp + ppend, e, depth, indent, version_req, verbose=verbose) for e in sorted(extras)]
+ return '\n'.join(filter(None, results))
+ return ""
+
+ if pp not in self.distro:
+ return ""
+
+ rawtext = json.dumps(self._get_dependency_tree(pp, extra, version_req, depth, verbose=verbose, upward=True), indent=indent)
+ lines = [l for l in rawtext.split("\n") if len(l.strip()) > 2 and ( ppend=="" or not "[requires:" in l)]
+ return "\n".join(filter(None, lines)).replace('"', "").replace('[requires :', '[requires:')
+
+ def description(self, pp: str) -> None:
+ """Return package description or None if not found."""
+ if pp in self.distro:
+ return print("\n".join(self.distro[pp]["description"].split(r"\n")))
+
+ def summary(self, pp: str) -> str:
+ """Return package summary or empty string if not found."""
+ if pp in self.distro:
+ return self.distro[pp]["summary"]
+ return ""
+
+ def pip_list(self, full: bool = False, max_length: int = 144) -> List[Tuple[str, Union[str, Tuple[str, str]]]]:
+ """List installed packages with optional details.
+
+ :param full: Whether to include the package version and summary
+ :param max_length: The maximum length for the summary
+ :return: List of tuples containing package information
+ """
+ pkgs = sorted(self.distro.items())
+ if full:
+ return [(p, d["version"], utils.sum_up(d["summary"], max_length)) for p, d in pkgs]
+ return [(p, d["version"]) for p, d in pkgs]
diff --git a/wppm/utils.py b/wppm/utils.py
new file mode 100644
index 00000000..16287244
--- /dev/null
+++ b/wppm/utils.py
@@ -0,0 +1,355 @@
+# -*- coding: utf-8 -*-
+#
+# WinPython utilities
+# Copyright © 2012 Pierre Raybaut
+# Copyright © 2014-2025+ The Winpython development team https://github.com/winpython/
+# Licensed under the terms of the MIT License
+# (see winpython/__init__.py for details)
+
+import os
+import sys
+import stat
+import shutil
+import locale
+import subprocess
+from pathlib import Path
+import re
+import tarfile
+import zipfile
+
+# SOURCE_PATTERN defines what an acceptable source package name is
+SOURCE_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z]*[\-]?[0-9]*)(\.zip|\.tar\.gz|\-(py[2-7]*|py[2-7]*\.py[2-7]*)\-none\-any\.whl)'
+
+# WHEELBIN_PATTERN defines what an acceptable binary wheel package is
+WHEELBIN_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z0-9\+]*[0-9]?)-cp([0-9]*)\-[0-9|c|o|n|e|p|m]*\-(win32|win\_amd64)\.whl'
+
+def get_python_executable(path=None):
+ """Return the path to the Python executable."""
+ python_path = Path(path) if path else Path(sys.executable)
+ base_dir = python_path if python_path.is_dir() else python_path.parent
+ python_exe = base_dir / 'python.exe'
+ pypy_exe = base_dir / 'pypy3.exe' # For PyPy
+ return str(python_exe if python_exe.is_file() else pypy_exe)
+
+def get_site_packages_path(path=None):
+ """Return the path to the Python site-packages directory."""
+ python_path = Path(path) if path else Path(sys.executable)
+ base_dir = python_path if python_path.is_dir() else python_path.parent
+ site_packages = base_dir / 'Lib' / 'site-packages'
+ pypy_site_packages = base_dir / 'site-packages' # For PyPy
+ return str(pypy_site_packages if pypy_site_packages.is_dir() else site_packages)
+
+def get_installed_tools(path=None)-> str:
+ """Generates Markdown for installed tools section in package index."""
+ tool_lines = []
+ python_exe = Path(get_python_executable(path))
+ version = exec_shell_cmd(f'powershell (Get-Item {python_exe}).VersionInfo.FileVersion', python_exe.parent).splitlines()[0]
+ tool_lines.append(("Python" ,f"http://www.python.org/", version, "Python programming language with standard library"))
+ if (node_exe := python_exe.parent.parent / "n" / "node.exe").exists():
+ version = exec_shell_cmd(f'powershell (Get-Item {node_exe}).VersionInfo.FileVersion', node_exe.parent).splitlines()[0]
+ tool_lines.append(("Nodejs", "https://nodejs.org", version, "a JavaScript runtime built on Chrome's V8 JavaScript engine"))
+
+ if (pandoc_exe := python_exe.parent.parent / "t" / "pandoc.exe").exists():
+ version = exec_shell_cmd("pandoc -v", pandoc_exe.parent).splitlines()[0].split(" ")[-1]
+ tool_lines.append(("Pandoc", "https://pandoc.org", version, "an universal document converter"))
+
+ if (vscode_exe := python_exe.parent.parent / "t" / "VSCode" / "Code.exe").exists():
+ version = exec_shell_cmd(f'powershell (Get-Item {vscode_exe}).VersionInfo.FileVersion', vscode_exe.parent).splitlines()[0]
+ tool_lines.append(("VSCode","https://code.visualstudio.com", version, "a source-code editor developed by Microsoft"))
+ return tool_lines
+
+def onerror(function, path, excinfo):
+ """Error handler for `shutil.rmtree`."""
+ if not os.access(path, os.W_OK):
+ os.chmod(path, stat.S_IWUSR)
+ function(path)
+ else:
+ raise
+
+def sum_up(text: str, max_length: int = 144, stop_at: str = ". ") -> str:
+ """Summarize text to fit within max_length, ending at last complete sentence."""
+ summary = (text + os.linesep).splitlines()[0].strip()
+ if len(summary) <= max_length:
+ return summary
+ if stop_at and stop_at in summary[:max_length]:
+ return summary[:summary.rfind(stop_at, 0, max_length)] + stop_at.strip()
+ return summary[:max_length].strip()
+
+def print_box(text):
+ """Print text in a box"""
+ line0 = "+" + ("-" * (len(text) + 2)) + "+"
+ line1 = "| " + text + " |"
+ print("\n\n" + "\n".join([line0, line1, line0]) + "\n")
+
+def is_python_distribution(path):
+ """Return True if path is a Python distribution."""
+ has_exec = Path(get_python_executable(path)).is_file()
+ has_site = Path(get_site_packages_path(path)).is_dir()
+ return has_exec and has_site
+
+def decode_fs_string(string):
+ """Convert string from file system charset to unicode."""
+ charset = sys.getfilesystemencoding() or locale.getpreferredencoding()
+ return string.decode(charset)
+
+def exec_shell_cmd(args, path):
+ """Execute shell command (*args* is a list of arguments) in *path*."""
+ process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=path, shell=True)
+ return decode_fs_string(process.stdout.read())
+
+def exec_run_cmd(args, path=None):
+ """Run a single command (*args* is a list of arguments) in optional *path*."""
+ process = subprocess.run(args, capture_output=True, cwd=path, text=True)
+ return process.stdout
+
+def python_query(cmd, path):
+ """Execute Python command using the Python interpreter located in *path*."""
+ the_exe = get_python_executable(path)
+ return exec_shell_cmd(f'"{the_exe}" -c "{cmd}"', path).splitlines()[0]
+
+def python_execmodule(cmd, path):
+ """Execute Python command using the Python interpreter located in *path*."""
+ the_exe = get_python_executable(path)
+ exec_shell_cmd(f'{the_exe} -m {cmd}', path)
+
+def get_python_infos(path):
+ """Return (version, architecture) for the Python distribution located in *path*."""
+ is_64 = python_query("import sys; print(sys.maxsize > 2**32)", path)
+ arch = {"True": 64, "False": 32}.get(is_64, None)
+ ver = python_query("import sys;print(f'{sys.version_info.major}.{sys.version_info.minor}')", path)
+ return ver, arch
+
+def get_python_long_version(path):
+ """Return long version (X.Y.Z) for the Python distribution located in *path*."""
+ ver = python_query("import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')", path)
+ return ver if re.match(r"([0-9]*)\.([0-9]*)\.([0-9]*)", ver) else None
+
+def patch_shebang_line(fname, pad=b" ", to_movable=True, targetdir=""):
+ """Remove absolute path to python.exe in shebang lines in binary files, or re-add it."""
+ target_dir = targetdir if to_movable else os.path.abspath(os.path.join(os.path.dirname(fname), r"..")) + "\\"
+ executable = sys.executable
+ shebang_line = re.compile(rb"""(#!.*pythonw?\.exe)"?""") # Python3+
+ if "pypy3" in sys.executable:
+ shebang_line = re.compile(rb"""(#!.*pypy3w?\.exe)"?""") # Pypy3+
+ target_dir = target_dir.encode("utf-8")
+
+ with open(fname, "rb") as fh:
+ initial_content = fh.read()
+ content = shebang_line.split(initial_content, maxsplit=1)
+ if len(content) != 3:
+ return
+ exe = os.path.basename(content[1][2:])
+ content[1] = b"#!" + target_dir + exe # + (pad * (len(content[1]) - len(exe) - 2))
+ final_content = b"".join(content)
+ if initial_content == final_content:
+ return
+ try:
+ with open(fname, "wb") as fo:
+ fo.write(final_content)
+ print("patched", fname)
+ except Exception:
+ print("failed to patch", fname)
+
+def patch_shebang_line_py(fname, to_movable=True, targetdir=""):
+ """Changes shebang line in '.py' file to relative or absolue path"""
+ import fileinput
+ exec_path = r'#!.\python.exe' if to_movable else '#!' + sys.executable
+ if 'pypy3' in sys.executable:
+ exec_path = r'#!.\pypy3.exe' if to_movable else exec_path
+ for line in fileinput.input(fname, inplace=True):
+ if re.match(r'^#\!.*python\.exe$', line) or re.match(r'^#\!.*pypy3\.exe$', line):
+ print(exec_path)
+ else:
+ print(line, end='')
+
+def guess_encoding(csv_file):
+ """guess the encoding of the given file"""
+ with open(csv_file, "rb") as f:
+ data = f.read(5)
+ if data.startswith(b"\xEF\xBB\xBF"): # UTF-8 with a "BOM" (normally no BOM in utf-8)
+ return ["utf-8-sig"]
+ try:
+ with open(csv_file, encoding="utf-8") as f:
+ preview = f.read(222222)
+ return ["utf-8"]
+ except:
+ return [locale.getdefaultlocale()[1], "utf-8"]
+
+def replace_in_file(filepath: Path, replacements: list[tuple[str, str]], filedest: Path = None, verbose=False):
+ """
+ Replaces strings in a file
+ Args:
+ filepath: Path to the file to modify.
+ replacements: A list of tuples of ('old string 'new string')
+ filedest: optional output file, otherwise will be filepath
+ """
+ the_encoding = guess_encoding(filepath)[0]
+ with open(filepath, "r", encoding=the_encoding) as f:
+ content = f.read()
+ new_content = content
+ for old_text, new_text in replacements:
+ new_content = new_content.replace(old_text, new_text)
+ outfile = filedest if filedest else filepath
+ if new_content != content or str(outfile) != str(filepath):
+ with open(outfile, "w", encoding=the_encoding) as f:
+ f.write(new_content)
+ if verbose:
+ print(f"patched from {Path(filepath).name} into {outfile} !")
+
+def patch_sourcefile(fname, in_text, out_text, silent_mode=False):
+ """Replace a string in a source file."""
+ if not silent_mode:
+ print(f"patching {fname} from {in_text} to {out_text}")
+ if Path(fname).is_file() and in_text != out_text:
+ replace_in_file(Path(fname), [(in_text, out_text)])
+
+def extract_archive(fname, targetdir=None, verbose=False):
+ """Extract .zip, .exe or .tar.gz archive to a temporary directory.
+ Return the temporary directory path"""
+ targetdir = targetdir or create_temp_dir()
+ Path(targetdir).mkdir(parents=True, exist_ok=True)
+ if Path(fname).suffix in ('.zip', '.exe'):
+ obj = zipfile.ZipFile(fname, mode="r")
+ elif fname.endswith('.tar.gz'):
+ obj = tarfile.open(fname, mode='r:gz')
+ else:
+ raise RuntimeError(f"Unsupported archive filename {fname}")
+ obj.extractall(path=targetdir)
+ return targetdir
+
+def get_source_package_infos(fname):
+ """Return a tuple (name, version) of the Python source package."""
+ if fname.endswith('.whl'):
+ return Path(fname).name.split("-")[:2]
+ match = re.match(SOURCE_PATTERN, Path(fname).name)
+ return match.groups()[:2] if match else None
+
+def buildflit_wininst(root, python_exe=None, copy_to=None, verbose=False):
+ """Build Wheel from Python package located in *root* with flit."""
+ python_exe = python_exe or sys.executable
+ cmd = [python_exe, '-m', 'flit', 'build']
+ if verbose:
+ subprocess.call(cmd, cwd=root)
+ else:
+ subprocess.Popen(cmd, cwd=root, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ distdir = Path(root) / 'dist'
+ if not distdir.is_dir():
+ raise RuntimeError(
+ "Build failed: see package README file for further details regarding installation requirements.\n\n"
+ "For more concrete debugging infos, please try to build the package from the command line:\n"
+ "1. Open a WinPython command prompt\n"
+ "2. Change working directory to the appropriate folder\n"
+ "3. Type `python -m flit build`"
+ )
+ for distname in os.listdir(distdir):
+ if re.match(SOURCE_PATTERN, distname) or re.match(WHEELBIN_PATTERN, distname):
+ break
+ else:
+ raise RuntimeError(f"Build failed: not a pure Python package? {distdir}")
+
+ src_fname = distdir / distname
+ if copy_to:
+ dst_fname = Path(copy_to) / distname
+ shutil.move(src_fname, dst_fname)
+ if verbose:
+ print(f"Move: {src_fname} --> {dst_fname}")
+
+def direct_pip_install(fname, python_exe=None, verbose=False, install_options=None):
+ """Direct install via python -m pip !"""
+ python_exe = python_exe or sys.executable
+ myroot = Path(python_exe).parent
+ cmd = [python_exe, "-m", "pip", "install"] + (install_options or []) + [fname]
+ if not verbose:
+ process = subprocess.Popen(cmd, cwd=myroot, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ the_log = f"{stdout}\n {stderr}"
+ if " not find " in the_log or " not found " in the_log:
+ print(f"Failed to Install: \n {fname} \n msg: {the_log}")
+ raise RuntimeError
+ process.stdout.close()
+ process.stderr.close()
+ else:
+ subprocess.call(cmd, cwd=myroot)
+ print(f"Installed {fname} via {' '.join(cmd)}")
+ return fname
+
+def do_script(this_script, python_exe=None, copy_to=None, verbose=False, install_options=None):
+ """Execute a script (get-pip typically)."""
+ python_exe = python_exe or sys.executable
+ myroot = Path(python_exe).parent
+ # cmd = [python_exe, myroot + r'\Scripts\pip-script.py', 'install']
+ cmd = [python_exe] + (install_options or []) + ([this_script] if this_script else [])
+ print("Executing ", cmd)
+ if not verbose:
+ subprocess.Popen(cmd, cwd=myroot, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ else:
+ subprocess.call(cmd, cwd=myroot)
+ print("Executed ", cmd)
+ return 'ok'
+
+def columns_width(list_of_lists):
+ """Return the maximum string length of each column of a list of lists."""
+ if not isinstance(list_of_lists, list):
+ return [0]
+ return [max(len(str(item)) for item in sublist) for sublist in zip(*list_of_lists)]
+
+def formatted_list(list_of_list, full=False, max_width=70):
+ """Format a list_of_list to fixed length columns."""
+ columns_size = columns_width(list_of_list)
+ columns = range(len(columns_size))
+ return [list(line[col].ljust(columns_size[col])[:max_width] for col in columns) for line in list_of_list]
+
+def normalize(this):
+ """Apply PEP 503 normalization to the string."""
+ return re.sub(r"[-_.]+", "-", this).lower()
+
+def canonicalize_name(this):
+ """Apply PEP 503 normalization to the string."""
+ return re.sub(r"[-_.]+", "-", this).lower()
+
+def zip_directory(folder_path, output_zip_path):
+ folder_path = Path(folder_path)
+ output_zip_path = Path(output_zip_path)
+
+ with zipfile.ZipFile(output_zip_path, 'w', compression=zipfile.ZIP_DEFLATED) as zipf:
+ for file in folder_path.rglob('*'):
+ if file.is_file():
+ arcname = file.relative_to(folder_path)
+ zipf.write(file, arcname)
+
+def find_7zip_executable() -> str:
+ """Locates the 7-Zip executable (7z.exe)."""
+ possible_program_files = [r"C:\Program Files", r"C:\Program Files (x86)", Path(sys.prefix).parent / "t"]
+ for base_dir in possible_program_files:
+ if (executable_path := Path(base_dir) / "7-Zip" / "7z.exe").is_file():
+ return str(executable_path)
+ raise RuntimeError("7ZIP is not installed on this computer.")
+
+def create_installer_7zip(origin, destination, filename_stem, installer_type: str = "exe", compression= "mx5"):
+ """Creates a WinPython installer using 7-Zip: "exe", "7z", "zip")"""
+ fullfilename = destination / (filename_stem + "." + installer_type)
+ if installer_type not in ["exe", "7z", "zip"]:
+ return
+ sfx_option = "-sfx7z.sfx" if installer_type == "exe" else ""
+ zip_option = "-tzip" if installer_type == "zip" else ""
+ compress_level = "mx5" if compression == "" else compression
+ command = f'"{find_7zip_executable()}" {zip_option} -{compress_level} a "{fullfilename}" "{origin}" {sfx_option}'
+ print(f'Executing 7-Zip script: "{command}"')
+ try:
+ subprocess.run(command, shell=True, check=True, stderr=sys.stderr, stdout=sys.stderr)
+ except subprocess.CalledProcessError as e:
+ print(f"Error executing 7-Zip script: {e}", file=sys.stderr)
+
+def command_installer_7zip(origin, destination, filename_stem, create_installer: str = "exe"):
+ for commmand in create_installer.lower().replace("7zip",".exe").split('.'):
+ installer_type, compression = (commmand + "-").split("-")[:2]
+ create_installer_7zip(Path(origin), Path(destination), filename_stem, installer_type, compression)
+
+if __name__ == '__main__':
+ print_box("Test")
+ dname = sys.prefix
+ print((dname + ':', '\n', get_python_infos(dname)))
+
+ tmpdir = r'D:\Tests\winpython_tests'
+ Path(tmpdir).mkdir(parents=True, exist_ok=True)
+ print(extract_archive(str(Path(r'D:\WinP\bd37') / 'packages.win-amd64' / 'python-3.7.3.amd64.zip'), tmpdir))
diff --git a/wppm/wheelhouse.py b/wppm/wheelhouse.py
new file mode 100644
index 00000000..7ed9e54f
--- /dev/null
+++ b/wppm/wheelhouse.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python3
+"""
+WheelHouse.py - manage WinPython local WheelHouse.
+"""
+import sys
+from pathlib import Path
+from collections import defaultdict
+import shutil
+import subprocess
+from typing import Dict, List, Optional, Tuple
+from . import packagemetadata as pm
+
+# Use tomllib if available (Python 3.11+), otherwise fall back to tomli
+try:
+ import tomllib # Python 3.11+
+except ImportError:
+ try:
+ import tomli as tomllib # For older Python versions
+ except ImportError:
+ print("Please install tomli for Python < 3.11: pip install tomli")
+ sys.exit(1)
+
+def parse_pylock_toml(path: Path) -> Dict[str, Dict[str, str | List[str]]]:
+ """Parse a pylock.toml file and extract package information."""
+ with open(path, "rb") as f:
+ data = tomllib.load(f)
+
+ # This dictionary maps package names to (version, [hashes])
+ package_hashes = defaultdict(lambda: {"version": "", "hashes": []})
+
+ for entry in data.get("packages", []):
+ name = entry["name"]
+ version = entry["version"]
+ all_hashes = []
+
+ # Handle wheels
+ for wheel in entry.get("wheels", []):
+ sha256 = wheel.get("hashes", {}).get("sha256")
+ if sha256:
+ all_hashes.append(sha256)
+
+ # Handle sdist (if present)
+ sdist = entry.get("sdist")
+ if sdist and "hashes" in sdist:
+ sha256 = sdist["hashes"].get("sha256")
+ if sha256:
+ all_hashes.append(sha256)
+
+ package_hashes[name]["version"] = version
+ package_hashes[name]["hashes"].extend(all_hashes)
+
+ return package_hashes
+
+def write_requirements_txt(package_hashes: Dict[str, Dict[str, str | List[str]]], output_path: Path) -> None:
+ """Write package requirements to a requirements.txt file."""
+ with open(output_path, "w") as f:
+ for name, data in sorted(package_hashes.items()):
+ version = data["version"]
+ hashes = data["hashes"]
+
+ if hashes:
+ f.write(f"{name}=={version} \\\n")
+ for i, h in enumerate(hashes):
+ end = " \\\n" if i < len(hashes) - 1 else "\n"
+ f.write(f" --hash=sha256:{h}{end}")
+ else:
+ f.write(f"{name}=={version}\n")
+
+ print(f"✅ requirements.txt written to {output_path}")
+
+def pylock_to_req(path: Path, output_path: Optional[Path] = None) -> None:
+ """Convert a pylock.toml file to requirements.txt."""
+ pkgs = parse_pylock_toml(path)
+ if not output_path:
+ output_path = path.parent / (path.stem.replace('pylock', 'requirement_with_hash') + '.txt')
+ write_requirements_txt(pkgs, output_path)
+
+def run_pip_command(command: List[str], check: bool = True, capture_output=True) -> Tuple[bool, Optional[str]]:
+ """Run a pip command and return the result."""
+ print('\n', ' '.join(command),'\n')
+ try:
+ result = subprocess.run(
+ command,
+ capture_output=capture_output,
+ text=True,
+ check=check
+ )
+ return (result.returncode == 0), (result.stderr or result.stdout)
+ except subprocess.CalledProcessError as e:
+ return False, e.stderr
+ except FileNotFoundError:
+ return False, "pip or Python not found."
+ except Exception as e:
+ return False, f"Unexpected error: {e}"
+
+def get_wheels(requirements: Path, wheeldrain: Path, wheelorigin: Optional[Path] = None
+ , only_check: bool = True,post_install: bool = False) -> bool:
+ """Download or check Python wheels based on requirements."""
+ added = []
+ if wheelorigin:
+ added = ['--no-index', '--trusted-host=None', f'--find-links={wheelorigin}']
+ pre_checks = [sys.executable, "-m", "pip", "install", "--dry-run", "--no-deps", "--require-hashes", "-r", str(requirements)] + added
+ instruction = [sys.executable, "-m", "pip", "download", "--no-deps", "--require-hashes", "-r", str(requirements), "--dest", str(wheeldrain)] + added
+ if wheeldrain:
+ added = ['--no-index', '--trusted-host=None', f'--find-links={wheeldrain}']
+ post_install_cmd = [sys.executable, "-m", "pip", "install", "--no-deps", "--require-hashes", "-r", str(requirements)] + added
+
+ # Run pip dry-run, only if a move of wheels
+ if wheelorigin and wheelorigin != wheeldrain:
+ success, output = run_pip_command(pre_checks, check=False)
+ if not success:
+ print("❌ Dry-run failed. Here's the output:\n")
+ print(output or "")
+ return False
+
+ print("✅ Requirements can be installed successfully (dry-run passed).\n")
+
+ # All ok
+ if only_check and not post_install:
+ return True
+
+ # Want to install
+ if not only_check and post_install:
+ success, output = run_pip_command(post_install_cmd, check=False, capture_output=False)
+ if not success:
+ print("❌ Installation failed. Here's the output:\n")
+ print(output or "")
+ return False
+ return True
+
+ # Otherwise download also, but not install direct
+ success, output = run_pip_command(instruction)
+ if not success:
+ print("❌ Download failed. Here's the output:\n")
+ print(output or "")
+ return False
+
+ return True
+
+def get_pylock_wheels(wheelhouse: Path, lockfile: Path, wheelorigin: Optional[Path] = None, wheeldrain: Optional[Path] = None) -> None:
+ """Get wheels asked pylock file."""
+ filename = Path(lockfile).name
+ wheelhouse.mkdir(parents=True, exist_ok=True)
+ trusted_wheelhouse = wheelhouse / "included.wheels"
+ trusted_wheelhouse.mkdir(parents=True, exist_ok=True)
+
+ filename_lock = wheelhouse / filename
+ filename_req = wheelhouse / (Path(lockfile).stem.replace('pylock', 'requirement') + '.txt')
+
+ pylock_to_req(Path(lockfile), filename_req)
+
+ if not str(Path(lockfile)) == str(filename_lock):
+ shutil.copy2(lockfile, filename_lock)
+
+ # We create a destination for wheels that is specific, so we can check all is there
+ destination_wheelhouse = Path(wheeldrain) if wheeldrain else wheelhouse / Path(lockfile).name.replace('.toml', '.wheels')
+ destination_wheelhouse.mkdir(parents=True, exist_ok=True)
+ # there can be an override
+
+ in_trusted = False
+
+ if wheelorigin is None:
+ # Try from trusted WheelHouse
+ print(f"\n\n*** Checking if we can install from our Local WheelHouse: ***\n {trusted_wheelhouse}\n\n")
+ in_trusted = get_wheels(filename_req, destination_wheelhouse, wheelorigin=trusted_wheelhouse, only_check=True)
+ if in_trusted:
+ print(f"\n\n*** We can install from Local WheelHouse: ***\n {trusted_wheelhouse}\n\n")
+ in_installed = get_wheels(filename_req, trusted_wheelhouse, wheelorigin=trusted_wheelhouse, only_check=False, post_install=True)
+
+ if not in_trusted:
+ post_install = True if wheelorigin and Path(wheelorigin).is_dir and Path(wheelorigin).samefile(destination_wheelhouse) else False
+ if post_install:
+ print(f"\n\n*** Installing from Local WheelHouse: ***\n {destination_wheelhouse}\n\n")
+ else:
+ print(f"\n\n*** Re-Checking if we can install from: {'pypi.org' if not wheelorigin or wheelorigin == '' else wheelorigin}\n\n")
+
+ in_pylock = get_wheels(filename_req, destination_wheelhouse, wheelorigin=wheelorigin, only_check=False, post_install=post_install)
+ if in_pylock:
+ if not post_install:
+ print(f"\n\n*** You can now install from this dedicated WheelHouse: ***\n {destination_wheelhouse}")
+ print(f"\n via:\n wppm {filename_lock} -wh {destination_wheelhouse}\n")
+ else:
+ print(f"\n\n*** We can't install {filename} ! ***\n\n")
+
+def list_packages_with_metadata(directory: str) -> List[Tuple[str, str, str]]:
+ "get metadata from a Wheelhouse directory"
+ packages = pm.get_directory_metadata(directory)
+ results = [ (p.name, p.version, p.summary) for p in packages]
+ return results
+
+def main() -> None:
+ """Main entry point for the script."""
+ if len(sys.argv) != 2:
+ print("Usage: python pylock_to_requirements.py pylock.toml")
+ sys.exit(1)
+
+ path = Path(sys.argv[1])
+ if not path.exists():
+ print(f"❌ File not found: {path}")
+ sys.exit(1)
+
+ pkgs = parse_pylock_toml(path)
+ dest = path.parent / (path.stem.replace('pylock', 'requirement_with_hash') + '.txt')
+ write_requirements_txt(pkgs, dest)
+
+if __name__ == "__main__":
+ main()
diff --git a/wppm/wppm.py b/wppm/wppm.py
new file mode 100644
index 00000000..73e93b38
--- /dev/null
+++ b/wppm/wppm.py
@@ -0,0 +1,404 @@
+# -*- coding: utf-8 -*-
+#
+# WinPython Package Manager
+# Copyright © 2012 Pierre Raybaut
+# Copyright © 2014-2025+ The Winpython development team https://github.com/winpython/
+# Licensed under the terms of the MIT License
+# (see wppm/__init__.py for details)
+
+import os
+import re
+import sys
+import shutil
+import subprocess
+import json
+from pathlib import Path
+from argparse import ArgumentParser, RawTextHelpFormatter
+from . import utils, piptree, associate, diff, __version__
+from . import wheelhouse as wh
+from operator import itemgetter
+# Workaround for installing PyVISA on Windows from source:
+os.environ["HOME"] = os.environ["USERPROFILE"]
+
+class Package:
+ """Standardize a Package from filename or pip list."""
+ def __init__(self, fname: str, suggested_summary: str = None):
+ self.fname = fname
+ self.description = (utils.sum_up(suggested_summary) if suggested_summary else "").strip()
+ self.name, self.version = fname, '?.?.?'
+ if fname.lower().endswith((".zip", ".tar.gz", ".whl")):
+ bname = Path(self.fname).name # e.g., "sqlite_bro-1.0.0..."
+ infos = utils.get_source_package_infos(bname) # get name, version
+ if infos:
+ self.name, self.version = utils.normalize(infos[0]), infos[1]
+ self.url = f"https://pypi.org/project/{self.name}"
+ self.files = []
+
+ def __str__(self):
+ return f"{self.name} {self.version}\r\n{self.description}\r\nWebsite: {self.url}"
+
+
+class Distribution:
+ """Handles operations on a WinPython distribution."""
+ def __init__(self, target: str = None, verbose: bool = False):
+ self.target = target or str(Path(sys.executable).parent) # Default target more explicit
+ self.verbose = verbose
+ self.pip = None
+ self.to_be_removed = []
+ self.version, self.architecture = utils.get_python_infos(self.target)
+ self.python_exe = utils.get_python_executable(self.target)
+ self.short_exe = Path(self.python_exe).name
+ self.wheelhouse = Path(self.target).parent / "wheelhouse"
+
+ def create_file(self, package, name, dstdir, contents):
+ """Generate data file -- path is relative to distribution root dir"""
+ dst = Path(dstdir) / name
+ if self.verbose:
+ print(f"create: {dst}")
+ full_dst = Path(self.target) / dst
+ with open(full_dst, "w") as fd:
+ fd.write(contents)
+ package.files.append(str(dst))
+
+ def get_installed_packages(self, update: bool = False) -> list[Package]:
+ """Return installed packages."""
+ if str(Path(sys.executable).parent) == self.target:
+ self.pip = piptree.PipData()
+ else:
+ self.pip = piptree.PipData(utils.get_python_executable(self.target))
+ pip_list = self.pip.pip_list(full=True)
+ return [Package(f"{i[0].replace('-', '_').lower()}-{i[1]}-py3-none-any.whl", suggested_summary=i[2]) for i in pip_list]
+
+ def render_markdown_for_list(self, title, items):
+ """Generates a Markdown section; name, url, version, summary"""
+ md = f"### {title}\n\n"
+ md += "Name | Version | Description\n"
+ md += "-----|---------|------------\n"
+ for name, url, version, summary in sorted(items, key=lambda p: (p[0].lower(), p[2])):
+ md += f"[{name}]({url}) | {version} | {summary}\n"
+ md += "\n"
+ return md
+
+ def generate_package_index_markdown(self, python_executable_directory: str|None = None, winpyver2: str|None = None,
+ flavor: str|None = None, architecture_bits: int|None = None
+ , release_level: str|None = None, wheeldir: str|None = None) -> str:
+ """Generates a Markdown formatted package index page."""
+ my_ver , my_arch = utils.get_python_infos(python_executable_directory or self.target)
+ my_winpyver2 = winpyver2 or os.getenv("WINPYVER2","")
+ my_winpyver2 = my_winpyver2 if my_winpyver2 != "" else my_ver
+ my_flavor = flavor or os.getenv("WINPYFLAVOR", "")
+ my_release_level = release_level or os.getenv("WINPYVER", "").replace(my_winpyver2+my_flavor, "")
+
+ tools_list = utils.get_installed_tools(utils.get_python_executable(python_executable_directory))
+ package_list = [(pkg.name, pkg.url, pkg.version, pkg.description) for pkg in self.get_installed_packages()]
+ wheelhouse_list = []
+ my_wheeldir = Path(wheeldir) if wheeldir else self.wheelhouse / 'included.wheels'
+ if my_wheeldir.is_dir():
+ wheelhouse_list = [(name, f"https://pypi.org/project/{name}", version, utils.sum_up(summary))
+ for name, version, summary in wh.list_packages_with_metadata(str(my_wheeldir)) ]
+
+ return f"""## WinPython {my_winpyver2 + my_flavor}
+
+The following packages are included in WinPython-{my_arch}bit v{my_winpyver2 + my_flavor} {my_release_level}.
+
+
+{self.render_markdown_for_list("Tools", tools_list)}
+{self.render_markdown_for_list("Python packages", package_list)}
+{self.render_markdown_for_list("WheelHouse packages", wheelhouse_list)}
+"""
+
+ def find_package(self, name: str) -> Package | None:
+ """Find installed package by name."""
+ for pack in self.get_installed_packages():
+ if utils.normalize(pack.name) == utils.normalize(name):
+ return pack
+
+ def patch_all_shebang(self, to_movable: bool = True, max_exe_size: int = 999999, targetdir: str = ""):
+ """Make all python launchers relative."""
+ for ffname in Path(self.target).glob("Scripts/*.exe"):
+ if ffname.stat().st_size <= max_exe_size:
+ utils.patch_shebang_line(ffname, to_movable=to_movable, targetdir=targetdir)
+ for ffname in Path(self.target).glob("Scripts/*.py"):
+ utils.patch_shebang_line_py(ffname, to_movable=to_movable, targetdir=targetdir)
+
+ def install(self, package: Package, install_options: list[str] = None):
+ """Install package in distribution."""
+ if package.fname.endswith((".whl", ".tar.gz", ".zip")) or (
+ ' ' not in package.fname and ';' not in package.fname and len(package.fname) >1): # Check extension with tuple
+ self.install_bdist_direct(package, install_options=install_options)
+ self.handle_specific_packages(package)
+ # minimal post-install actions
+ self.patch_standard_packages(package.name)
+
+ def do_pip_action(self, actions: list[str] = None, install_options: list[str] = None):
+ """Execute pip action in the distribution."""
+ my_list = install_options or []
+ my_actions = actions or []
+ executing = str(Path(self.target).parent / "scripts" / "env.bat")
+ if Path(executing).is_file():
+ complement = [r"&&", "cd", "/D", self.target, r"&&", utils.get_python_executable(self.target), "-m", "pip"]
+ else:
+ executing = utils.get_python_executable(self.target)
+ complement = ["-m", "pip"]
+ try:
+ fname = utils.do_script(this_script=None, python_exe=executing, verbose=self.verbose, install_options=complement + my_actions + my_list)
+ except RuntimeError as e:
+ if not self.verbose:
+ print("Failed!")
+ raise
+ else:
+ print(f"Pip action failed with error: {e}") # Print error if verbose
+
+ def patch_standard_packages(self, package_name="", to_movable=True):
+ """patch Winpython packages in need"""
+ import filecmp
+
+ # 'pywin32' minimal post-install (pywin32_postinstall.py do too much)
+ if package_name.lower() in ("", "pywin32"):
+ origin = Path(self.target) / "site-packages" / "pywin32_system32"
+ destin = Path(self.target)
+ if origin.is_dir():
+ for name in os.listdir(origin):
+ here, there = origin / name, destin / name
+ if not there.exists() or not filecmp.cmp(here, there):
+ shutil.copyfile(here, there)
+ # 'pip' to do movable launchers (around line 100) !!!!
+ # rational: https://github.com/pypa/pip/issues/2328
+ if package_name.lower() == "pip" or package_name == "":
+ # ensure pip will create movable launchers
+ # sheb_mov1 = classic way up to WinPython 2016-01
+ # sheb_mov2 = tried way, but doesn't work for pip (at least)
+ the_place = Path(self.target) / "lib" / "site-packages" / "pip" / "_vendor" / "distlib" / "scripts.py"
+ sheb_fix = " executable = get_executable()"
+ sheb_mov1 = " executable = os.path.join(os.path.basename(get_executable()))"
+ sheb_mov2 = " executable = os.path.join('..',os.path.basename(get_executable()))"
+ if to_movable:
+ utils.patch_sourcefile(the_place, sheb_fix, sheb_mov1)
+ utils.patch_sourcefile(the_place, sheb_mov2, sheb_mov1)
+ else:
+ utils.patch_sourcefile(the_place, sheb_mov1, sheb_fix)
+ utils.patch_sourcefile(the_place, sheb_mov2, sheb_fix)
+
+ # create movable launchers for previous package installations
+ self.patch_all_shebang(to_movable=to_movable)
+ if package_name.lower() in ("", "spyder"):
+ # spyder don't goes on internet without you ask
+ utils.patch_sourcefile(
+ Path(self.target) / "lib" / "site-packages" / "spyder" / "config" / "main.py",
+ "'check_updates_on_startup': True,",
+ "'check_updates_on_startup': False,",
+ )
+
+
+ def handle_specific_packages(self, package):
+ """Packages requiring additional configuration"""
+ if package.name.lower() in ("pyqt4", "pyqt5", "pyside2"):
+ # Qt configuration file (where to find Qt)
+ name = "qt.conf"
+ contents = """[Paths]\nPrefix = .\nBinaries = ."""
+ self.create_file(package, name, str(Path("Lib") / "site-packages" / package.name), contents)
+ self.create_file(package, name, ".", contents.replace(".", f"./Lib/site-packages/{package.name}"))
+ # pyuic script
+ if package.name.lower() == "pyqt5":
+ # see http://code.activestate.com/lists/python-list/666469/
+ tmp_string = r"""@echo off
+if "%WINPYDIR%"=="" call "%~dp0..\..\scripts\env.bat"
+"%WINPYDIR%\python.exe" -m PyQt5.uic.pyuic %1 %2 %3 %4 %5 %6 %7 %8 %9"""
+ else:
+ tmp_string = r"""@echo off
+if "%WINPYDIR%"=="" call "%~dp0..\..\scripts\env.bat"
+"%WINPYDIR%\python.exe" "%WINPYDIR%\Lib\site-packages\package.name\uic\pyuic.py" %1 %2 %3 %4 %5 %6 %7 %8 %9"""
+ # PyPy adaption: python.exe or pypy3.exe
+ my_exec = Path(utils.get_python_executable(self.target)).name
+ tmp_string = tmp_string.replace("python.exe", my_exec).replace("package.name", package.name)
+ self.create_file(package, f"pyuic{package.name[-1]}.bat", "Scripts", tmp_string)
+ # Adding missing __init__.py files (fixes Issue 8)
+ uic_path = str(Path("Lib") / "site-packages" / package.name / "uic")
+ for dirname in ("Loader", "port_v2", "port_v3"):
+ self.create_file(package, "__init__.py", str(Path(uic_path) / dirname), "")
+
+ def _print(self, package: Package, action: str):
+ """Print package-related action text."""
+ text = f"{action} {package.name} {package.version}"
+ if self.verbose:
+ utils.print_box(text)
+ else:
+ print(f" {text}...", end=" ")
+
+ def _print_done(self):
+ """Print OK at the end of a process"""
+ if not self.verbose:
+ print("OK")
+
+ def uninstall(self, package):
+ """Uninstall package from distribution"""
+ self._print(package, "Uninstalling")
+ if package.name != "pip":
+ # trick to get true target (if not current)
+ this_exec = utils.get_python_executable(self.target) # PyPy !
+ subprocess.call([this_exec, "-m", "pip", "uninstall", package.name, "-y"], cwd=self.target)
+ self._print_done()
+
+ def install_bdist_direct(self, package, install_options=None):
+ """Install a package directly !"""
+ self._print(package,f"Installing {package.fname.split('.')[-1]}")
+ try:
+ fname = utils.direct_pip_install(
+ package.fname,
+ python_exe=utils.get_python_executable(self.target), # PyPy !
+ verbose=self.verbose,
+ install_options=install_options,
+ )
+ except RuntimeError:
+ if not self.verbose:
+ print("Failed!")
+ raise
+ package = Package(fname)
+ self._print_done()
+
+def main(test=False):
+
+ registerWinPythonHelp = f"Register WinPython: associate file extensions, icons and context menu with this WinPython"
+ unregisterWinPythonHelp = f"Unregister WinPython: de-associate file extensions, icons and context menu from this WinPython"
+ parser = ArgumentParser(prog="wppm",
+ description=f"WinPython Package Manager: handle a WinPython Distribution and its packages ({__version__})",
+ formatter_class=RawTextHelpFormatter,
+ )
+ parser.add_argument("fname", metavar="package(s) or lockfile", nargs="*", default=[""], type=str, help="optional package names, wheels, or lockfile")
+ parser.add_argument("-v", "--verbose", action="store_true", help="show more details on packages and actions")
+ parser.add_argument( "--register", dest="registerWinPython", action="store_true", help=registerWinPythonHelp)
+ parser.add_argument("--unregister", dest="unregisterWinPython", action="store_true", help=unregisterWinPythonHelp)
+ parser.add_argument("--fix", action="store_true", help="make WinPython fix")
+ parser.add_argument("--movable", action="store_true", help="make WinPython movable")
+ parser.add_argument("-ws", dest="wheelsource", default=None, type=str, help="wheels location, '.' = WheelHouse): wppm pylock.toml -ws source_of_wheels, wppm -ls -ws .")
+ parser.add_argument("-wd", dest="wheeldrain" , default=None, type=str, help="wheels destination: wppm pylock.toml -wd destination_of_wheels")
+ parser.add_argument("-ls", "--list", action="store_true", help="list installed packages matching [optional] expression: wppm -ls, wppm -ls pand")
+ parser.add_argument("-lsa", dest="all", action="store_true",help=f"list details of packages matching [optional] expression: wppm -lsa pandas -l1")
+ parser.add_argument("-md", dest="markdown", action="store_true",help=f"markdown summary of the installation")
+ parser.add_argument("-p",dest="pipdown",action="store_true",help="show Package dependencies of the given package[option], [.]=all: wppm -p pandas[.]")
+ parser.add_argument("-r", dest="pipup", action="store_true", help=f"show Reverse (!= constraining) dependancies of the given package[option]: wppm -r pytest![test]")
+ parser.add_argument("-l", dest="levels", type=int, default=-1, help="show 'LEVELS' levels of dependencies (with -p, -r): wppm -p pandas -l1")
+ parser.add_argument("-t", dest="target", default=sys.prefix, help=f'path to target Python distribution (default: "{sys.prefix}")')
+ parser.add_argument("-i", "--install", action="store_true", help="install a given package wheel or pylock file (use pip for more features)")
+ parser.add_argument("-u", "--uninstall", action="store_true", help="uninstall package (use pip for more features)")
+
+ args = parser.parse_args()
+ targetpython = None
+ if args.target and args.target != sys.prefix:
+ targetpython = args.target if args.target.lower().endswith('.exe') else str(Path(args.target) / 'python.exe')
+ if args.wheelsource == ".": # play in default WheelHouse
+ if utils.is_python_distribution(args.target):
+ dist = Distribution(args.target)
+ args.wheelsource = dist.wheelhouse / 'included.wheels'
+ if args.install and args.uninstall:
+ raise RuntimeError("Incompatible arguments: --install and --uninstall")
+ if args.registerWinPython and args.unregisterWinPython:
+ raise RuntimeError("Incompatible arguments: --install and --uninstall")
+ if args.pipdown:
+ pip = piptree.PipData(targetpython, args.wheelsource)
+ for args_fname in args.fname:
+ pack, extra, *other = (args_fname + "[").replace("]", "[").split("[")
+ print(pip.down(pack, extra, args.levels if args.levels>0 else 2, verbose=args.verbose))
+ sys.exit()
+ elif args.pipup:
+ pip = piptree.PipData(targetpython, args.wheelsource)
+ for args_fname in args.fname:
+ pack, extra, *other = (args_fname + "[").replace("]", "[").split("[")
+ print(pip.up(pack, extra, args.levels if args.levels>=0 else 1, verbose=args.verbose))
+ sys.exit()
+ elif args.list:
+ pip = piptree.PipData(targetpython, args.wheelsource)
+ todo= []
+ for args_fname in args.fname:
+ todo += [l for l in pip.pip_list(full=True) if bool(re.search(args_fname, l[0]))]
+ todo = sorted(set(todo)) #, key=lambda p: (p[0].lower(), p[2])
+ titles = [['Package', 'Version', 'Summary'], ['_' * max(x, 6) for x in utils.columns_width(todo)]]
+ listed = utils.formatted_list(titles + todo, max_width=70)
+ for p in listed:
+ print(*p)
+ sys.exit()
+ elif args.all:
+ pip = piptree.PipData(targetpython, args.wheelsource)
+ for args_fname in args.fname:
+ todo = [l for l in pip.pip_list(full=True) if bool(re.search(args_fname, l[0]))]
+ for l in sorted(set(todo)):
+ title = f"** Package: {l[0]} **"
+ print("\n" + "*" * len(title), f"\n{title}", "\n" + "*" * len(title))
+ for key, value in pip.raw[l[0]].items():
+ rawtext = json.dumps(value, indent=2, ensure_ascii=False)
+ lines = [l for l in rawtext.split(r"\n") if len(l.strip()) > 2]
+ if key.lower() != 'description' or args.verbose:
+ print(f"{key}: ", "\n".join(lines).replace('"', ""))
+ sys.exit()
+ if args.registerWinPython:
+ print(registerWinPythonHelp)
+ if utils.is_python_distribution(args.target):
+ dist = Distribution(args.target)
+ else:
+ raise OSError(f"Invalid Python distribution {args.target}")
+ print(f"registering {args.target}")
+ print("continue ? Y/N")
+ theAnswer = input()
+ if theAnswer == "Y":
+ associate.register(dist.target, verbose=args.verbose)
+ sys.exit()
+ if args.unregisterWinPython:
+ print(unregisterWinPythonHelp)
+ if utils.is_python_distribution(args.target):
+ dist = Distribution(args.target)
+ else:
+ raise OSError(f"Invalid Python distribution {args.target}")
+ print(f"unregistering {args.target}")
+ print("continue ? Y/N")
+ theAnswer = input()
+ if theAnswer == "Y":
+ associate.unregister(dist.target, verbose=args.verbose)
+ sys.exit()
+ if utils.is_python_distribution(args.target):
+ dist = Distribution(args.target, verbose=True)
+ cmd_fix = rf"from wppm import wppm;dist=wppm.Distribution(r'{dist.target}');dist.patch_standard_packages('pip', to_movable=False)"
+ cmd_mov = rf"from wppm import wppm;dist=wppm.Distribution(r'{dist.target}');dist.patch_standard_packages('pip', to_movable=True)"
+ if args.fix:
+ # dist.patch_standard_packages('pip', to_movable=False) # would fail on wppm.exe
+ p = subprocess.Popen(["start", "cmd", "/k",dist.python_exe, "-c" , cmd_fix], shell = True, cwd=dist.target)
+ sys.exit()
+ if args.movable:
+ p = subprocess.Popen(["start", "cmd", "/k",dist.python_exe, "-c" , cmd_mov], shell = True, cwd=dist.target)
+ sys.exit()
+ if args.markdown:
+ default = dist.generate_package_index_markdown()
+ if args.wheelsource:
+ compare = dist.generate_package_index_markdown(wheeldir = args.wheelsource)
+ print(diff.compare_markdown_sections(default, compare,'python', 'wheelhouse', 'installed', 'wheelhouse'))
+ else:
+ print(default)
+ sys.exit()
+ if not args.install and not args.uninstall and args.fname[0].endswith(".toml"):
+ args.install = True # for Drag & Drop of .toml (and not wheel)
+ if args.fname[0] == "" or (not args.install and not args.uninstall):
+ parser.print_help()
+ sys.exit()
+ else:
+ try:
+ for args_fname in args.fname:
+ filename = Path(args_fname).name
+ install_from_wheelhouse = ["--no-index", "--trusted-host=None", f"--find-links={dist.wheelhouse / 'included.wheels'}"]
+ if filename.split('.')[0] == "pylock" and filename.split('.')[-1] == 'toml':
+ print(' a lock file !', args_fname, dist.target)
+ wh.get_pylock_wheels(dist.wheelhouse, Path(args_fname), args.wheelsource, args.wheeldrain)
+ sys.exit()
+ if args.uninstall:
+ package = dist.find_package(args_fname)
+ dist.uninstall(package)
+ elif args.install:
+ package = Package(args_fname)
+ if args.install:
+ dist.install(package, install_options=install_from_wheelhouse)
+ except NotImplementedError:
+ raise RuntimeError("Package is not (yet) supported by WPPM")
+ else:
+ raise OSError(f"Invalid Python distribution {args.target}")
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file