From 87e2bfd401dd8251ff52c372f05bbd974780bbae Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 18:40:21 +0000 Subject: [PATCH 001/148] Add C++ infrastructure: build, format, lint, and unit test tooling --- .clang-format | 31 ++++++++++++ .clang-tidy | 37 ++++++++++++++ Makefile | 30 +++++++++-- requirements/install_cpp_deps.sh | 40 +++++++++++++++ scripts/generate_compile_commands.py | 69 ++++++++++++++++++++++++++ setup.py | 42 ++++++++++++++++ tests/unit/cpp/CMakeLists.txt | 44 ++++++++++++++++ tests/unit/cpp/infrastructure_test.cpp | 14 ++++++ 8 files changed, 302 insertions(+), 5 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 requirements/install_cpp_deps.sh create mode 100644 scripts/generate_compile_commands.py create mode 100644 setup.py create mode 100644 tests/unit/cpp/CMakeLists.txt create mode 100644 tests/unit/cpp/infrastructure_test.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..f702e9dce --- /dev/null +++ b/.clang-format @@ -0,0 +1,31 @@ +# clang-format configuration for GiGL C++ sources. +# Run: clang-format -i (format in-place) +# clang-format --dry-run --Werror (check only) +BasedOnStyle: Google + +# Match the 100-column limit used for Python throughout the codebase. +ColumnLimit: 100 + +# 4-space indentation (Google style defaults to 2; override to match existing code). +IndentWidth: 4 +ContinuationIndentWidth: 4 + +# Align consecutive = signs in variable declarations for readability. +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + +# Keep short functions on one line only when they are truly trivial (getters/setters). +AllowShortFunctionsOnASingleLine: Inline + +# Never put if/else/loop bodies on the same line as the condition. +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false + +# Always break before the opening brace of a namespace, class, or function body. +BreakBeforeBraces: Attach + +# Sort #include blocks: standard library first, then project headers. +SortIncludes: CaseSensitive +IncludeBlocks: Regroup diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..2c746e6b2 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,37 @@ +# clang-tidy configuration for GiGL C++ sources. +# Run: clang-tidy -p build/compile_commands.json +# +# Checks are opt-in by prefix. Each line below enables (*) or disables (-) +# a category. More specific patterns override broader ones. + +Checks: > + clang-analyzer-*, + bugprone-use-after-move, + bugprone-incorrect-roundings, + bugprone-integer-division, + bugprone-signed-char-misuse, + bugprone-suspicious-memset-usage, + modernize-use-nullptr, + modernize-loop-convert, + modernize-use-override, + performance-unnecessary-value-param, + performance-unnecessary-copy-initialization, + readability-const-return-type, + -bugprone-easily-swappable-parameters, + -clang-analyzer-optin.cplusplus.UninitializedObject, + -modernize-use-trailing-return-type + +# Treat every enabled warning as an error so the build fails loudly. +WarningsAsErrors: "*" + +# Only apply header-file checks to GiGL-owned headers, not third-party +# (torch, pybind11) headers pulled in by includes. +HeaderFilterRegex: "gigl/.*" + +# Per-check configuration options. +CheckOptions: + # Enforce lower_case naming for local variables (matches existing style). + - key: readability-identifier-naming.LocalVariableCase + value: lower_case + - key: readability-identifier-naming.ParameterCase + value: lower_case diff --git a/Makefile b/Makefile index e15a063f3..11d8ba848 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG?=${DOCKER_IMAGE_MAIN_CPU_NAME}:${DATE} DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${DATE} PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts +CPP_SOURCES:=$(shell find gigl -name "*.cpp") PY_TEST_FILES?="*_test.py" # You can override GIGL_TEST_DEFAULT_RESOURCE_CONFIG by setting it in your environment i.e. # adding `export GIGL_TEST_DEFAULT_RESOURCE_CONFIG=your_resource_config` to your shell config (~/.bashrc, ~/.zshrc, etc.) @@ -49,6 +50,7 @@ install_dev_deps: check_if_valid_env gcloud auth configure-docker us-central1-docker.pkg.dev bash ./requirements/install_py_deps.sh --dev bash ./requirements/install_scala_deps.sh + bash ./requirements/install_cpp_deps.sh uv pip install -e . uv run pre-commit install --hook-type pre-commit --hook-type pre-push @@ -94,7 +96,12 @@ unit_test_scala: clean_build_files_scala # Eventually, we should look into splitting these up. # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. -unit_test: precondition_tests unit_test_py unit_test_scala +unit_test_cpp: + cmake -S tests/unit/cpp -B build/cpp_tests + cmake --build build/cpp_tests --parallel + ctest --test-dir build/cpp_tests --output-on-failure + +unit_test: precondition_tests unit_test_py unit_test_scala unit_test_cpp check_format_py: uv run autoflake --check --config pyproject.toml ${PYTHON_DIRS} @@ -109,7 +116,10 @@ check_format_md: @echo "Checking markdown files..." uv run mdformat --check ${MD_FILES} -check_format: check_format_py check_format_scala check_format_md +check_format_cpp: + clang-format --dry-run --Werror --style=file $(CPP_SOURCES) + +check_format: check_format_py check_format_scala check_format_md check_format_cpp # Set PY_TEST_FILES= to test a specifc file. # Ex. `make integration_test PY_TEST_FILES="dataflow_test.py"` @@ -143,12 +153,19 @@ format_md: @echo "Formatting markdown files..." uv run mdformat ${MD_FILES} -format: format_py format_scala format_md +format_cpp: + clang-format -i --style=file $(CPP_SOURCES) + +format: format_py format_scala format_md format_cpp type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs -lint_test: check_format assert_yaml_configs_parse +lint_cpp: build_cpp_extensions + uv run python scripts/generate_compile_commands.py + clang-tidy -p build/compile_commands.json $(CPP_SOURCES) + +lint_test: check_format assert_yaml_configs_parse lint_cpp @echo "Lint checks pass!" # compiles current working state of scala projects to local jars @@ -313,7 +330,10 @@ clean_build_files_scala: ( cd scala; sbt clean; find . -type d -name "target" -prune -exec rm -rf {} \; ) ( cd scala_spark35; sbt clean; find . -type d -name "target" -prune -exec rm -rf {} \; ) -clean_build_files: clean_build_files_py clean_build_files_scala +clean_build_files_cpp: + rm -rf build/ + +clean_build_files: clean_build_files_py clean_build_files_scala clean_build_files_cpp # Call to generate new proto definitions if any of the .proto files have been changed. # We intentionally rebuild *all* protos with one commmand as they should all be in sync. diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh new file mode 100644 index 000000000..9a3aacbd7 --- /dev/null +++ b/requirements/install_cpp_deps.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Install C++ development tools: clang-format, clang-tidy, cmake. +# +# Usage: +# bash requirements/install_cpp_deps.sh +# +# Called by `make install_dev_deps` alongside install_py_deps.sh and +# install_scala_deps.sh. + +set -e +set -x + +is_running_on_mac() { + [ "$(uname)" == "Darwin" ] + return $? +} + +if is_running_on_mac; then + # `brew install llvm` provides clang-format and clang-tidy. + # Homebrew does not add llvm to PATH by default to avoid shadowing Apple's + # clang, so we print an instruction for the developer to do it manually. + brew install llvm cmake + LLVM_PREFIX=$(brew --prefix llvm) + set +x + echo "" + echo "NOTE: Add the LLVM bin directory to your PATH to use clang-format and clang-tidy:" + echo " export PATH=\"${LLVM_PREFIX}/bin:\$PATH\"" + echo " (Add this to your ~/.zshrc or ~/.bashrc to make it permanent.)" + echo "" + set -x +else + # Ubuntu / Debian — clang 15 is the highest version available on Ubuntu 22.04. + apt-get install -y clang-format-15 clang-tidy-15 cmake + # Register versioned binaries as the default so bare `clang-format` and + # `clang-tidy` resolve to them without callers specifying the version suffix. + update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100 + update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 100 +fi + +echo "Finished installing C++ tooling" diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py new file mode 100644 index 000000000..8146f2c18 --- /dev/null +++ b/scripts/generate_compile_commands.py @@ -0,0 +1,69 @@ +"""Generate build/compile_commands.json for clang-tidy analysis of GiGL C++ extensions. + +clang-tidy needs a compilation database to resolve include paths and compiler flags. +This script derives those paths directly from the installed torch and pybind11 packages, +avoiding the need for `bear` or a separate CMake build of the extension. + +Usage:: + + uv run python scripts/generate_compile_commands.py + +Output: ``build/compile_commands.json`` (created or overwritten). +""" + +import json +import sys +import sysconfig +from pathlib import Path + + +def main() -> None: + try: + import pybind11 + import torch # noqa: F401 — imported to verify it is installed + from torch.utils.cpp_extension import include_paths as torch_include_paths + except ImportError as exc: + print( + f"Error: {exc}\n" + "Run `make build_cpp_extensions` first to ensure torch and pybind11 are available.", + file=sys.stderr, + ) + sys.exit(1) + + repo_root = Path(__file__).parent.parent.resolve() + + # Collect all include directories needed to compile the extension. + include_flags: list[str] = [] + for path in torch_include_paths(): + include_flags.append(f"-I{path}") + include_flags.append(f"-I{pybind11.get_include()}") + # Python C API headers (e.g. Python.h) required by pybind11. + include_flags.append(f"-I{sysconfig.get_path('include')}") + + cpp_sources = sorted((repo_root / "gigl").rglob("*.cpp")) + if not cpp_sources: + print("Warning: no .cpp files found under gigl/", file=sys.stderr) + + # Each entry in compile_commands.json describes how one source file is compiled. + # clang-tidy reads this to reproduce the exact compilation environment. + commands: list[dict[str, str]] = [ + { + "directory": str(repo_root), + "file": str(source), + "command": ( + f"c++ -std=c++17 -Wall -Wextra " + f"{' '.join(include_flags)} " + f"-c {source}" + ), + } + for source in cpp_sources + ] + + output = repo_root / "build" / "compile_commands.json" + output.parent.mkdir(exist_ok=True) + output.write_text(json.dumps(commands, indent=2)) + print(f"Wrote {len(commands)} entr{'y' if len(commands) == 1 else 'ies'} to {output}") + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..a9678da1f --- /dev/null +++ b/setup.py @@ -0,0 +1,42 @@ +from pathlib import Path + +from setuptools import setup +from torch.utils.cpp_extension import BuildExtension, CppExtension + + +def find_cpp_extensions() -> list[CppExtension]: + """Auto-discover pybind11 extension modules. + + Any .cpp file anywhere under ``gigl/`` is compiled as a Python C++ + extension. The module name is derived from the file path, so the + extension is importable at the same location as its Python neighbours. + + Example:: + + gigl/distributed/cpp_extensions/ppr_forward_push.cpp + → importable as ``gigl.distributed.cpp_extensions.ppr_forward_push`` + + To add a new extension, drop a .cpp file anywhere under ``gigl/`` — + no changes to this file required. + """ + extensions = [] + for cpp_file in sorted(Path("gigl").rglob("*.cpp")): + # Convert path separators to dots and strip the .cpp suffix to get the + # fully-qualified Python module name, e.g.: + # gigl/distributed/cpp_extensions/ppr_forward_push.cpp + # → "gigl.distributed.cpp_extensions.ppr_forward_push" + module_name = ".".join(cpp_file.with_suffix("").parts) + extensions.append( + CppExtension( + name=module_name, + sources=[str(cpp_file)], + extra_compile_args=["-O3", "-std=c++17", "-Wall", "-Wextra"], + ) + ) + return extensions + + +setup( + ext_modules=find_cpp_extensions(), + cmdclass={"build_ext": BuildExtension}, +) diff --git a/tests/unit/cpp/CMakeLists.txt b/tests/unit/cpp/CMakeLists.txt new file mode 100644 index 000000000..fd55255b2 --- /dev/null +++ b/tests/unit/cpp/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.18) +project(GiGLCppTests CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# --------------------------------------------------------------------------- +# GoogleTest via FetchContent +# --------------------------------------------------------------------------- +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz + # TODO: pin URL_HASH once infrastructure is validated, e.g.: + # URL_HASH SHA256= +) +# Prevent GoogleTest from overriding the compiler's runtime on Windows +# (no-op on Linux/Mac, but required for portable CMake config). +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +# Required for add_test() to register tests with CTest. +enable_testing() + +# --------------------------------------------------------------------------- +# Auto-discover test targets +# --------------------------------------------------------------------------- +# Any file named *_test.cpp in this directory (or subdirectories) is +# automatically compiled into its own test binary and registered with CTest. +# To add a new test suite, drop a *_test.cpp file here — no changes to this +# file required. This matches the *_test.py convention used for Python tests. +file(GLOB_RECURSE TEST_SOURCES "*_test.cpp") + +foreach(test_source ${TEST_SOURCES}) + # Derive the binary name from the filename, e.g.: + # ppr_forward_push_test.cpp → ppr_forward_push_test + get_filename_component(test_name ${test_source} NAME_WE) + add_executable(${test_name} ${test_source}) + target_link_libraries(${test_name} GTest::gtest_main) + # add_test registers the binary with CTest. Each *_test binary is one + # CTest entry; GoogleTest itself reports individual TEST() results inside it. + add_test(NAME ${test_name} COMMAND ${test_name}) +endforeach() diff --git a/tests/unit/cpp/infrastructure_test.cpp b/tests/unit/cpp/infrastructure_test.cpp new file mode 100644 index 000000000..d8d252f8e --- /dev/null +++ b/tests/unit/cpp/infrastructure_test.cpp @@ -0,0 +1,14 @@ +// Placeholder C++ unit test. +// +// This file exists to verify that the GoogleTest infrastructure compiles and +// runs end-to-end. Replace or supplement it with tests for actual GiGL C++ +// code (e.g. PPRForwardPushState) as those components are added. + +#include + +// A trivial sanity-check test — if this fails, something is very wrong with +// the build environment itself. +TEST(PlaceholderTest, BasicArithmetic) { + EXPECT_EQ(1 + 1, 2); + EXPECT_NE(1 + 1, 3); +} From a18fb47e53865408a0f3828ae82d5da130228565 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 18:48:13 +0000 Subject: [PATCH 002/148] =?UTF-8?q?Remove=20pybind11=20import=20from=20gen?= =?UTF-8?q?erate=5Fcompile=5Fcommands=20=E2=80=94=20bundled=20in=20torch?= =?UTF-8?q?=20includes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/generate_compile_commands.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 8146f2c18..05873a486 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -19,13 +19,12 @@ def main() -> None: try: - import pybind11 import torch # noqa: F401 — imported to verify it is installed from torch.utils.cpp_extension import include_paths as torch_include_paths except ImportError as exc: print( f"Error: {exc}\n" - "Run `make build_cpp_extensions` first to ensure torch and pybind11 are available.", + "Run `make build_cpp_extensions` first to ensure torch is available.", file=sys.stderr, ) sys.exit(1) @@ -33,10 +32,11 @@ def main() -> None: repo_root = Path(__file__).parent.parent.resolve() # Collect all include directories needed to compile the extension. + # torch_include_paths() returns the torch headers, which already bundle + # pybind11 under torch/include/pybind11/ — no separate pybind11 import needed. include_flags: list[str] = [] for path in torch_include_paths(): include_flags.append(f"-I{path}") - include_flags.append(f"-I{pybind11.get_include()}") # Python C API headers (e.g. Python.h) required by pybind11. include_flags.append(f"-I{sysconfig.get_path('include')}") From c127f2b86568b69cf7c4fac4100bdcfaf8620e04 Mon Sep 17 00:00:00 2001 From: Yozen Liu Date: Wed, 25 Mar 2026 12:13:46 -0700 Subject: [PATCH 003/148] ppr seq --- .../graph_transformer/graph_transformer.py | 235 ++++++++-- gigl/transforms/graph_transformer.py | 431 +++++++++++++++--- .../graph_transformer_test.py | 205 ++++++++- .../unit/transforms/graph_transformer_test.py | 163 ++++++- 4 files changed, 918 insertions(+), 116 deletions(-) diff --git a/gigl/src/common/models/graph_transformer/graph_transformer.py b/gigl/src/common/models/graph_transformer/graph_transformer.py index 2d07b849d..4308b495f 100644 --- a/gigl/src/common/models/graph_transformer/graph_transformer.py +++ b/gigl/src/common/models/graph_transformer/graph_transformer.py @@ -11,6 +11,7 @@ replacement as the encoder in ``LinkPredictionGNN``. """ +import math from typing import Callable, Literal, Optional, cast import torch @@ -20,7 +21,10 @@ from torch import Tensor from gigl.src.common.types.graph_data import EdgeType, NodeType -from gigl.transforms.graph_transformer import heterodata_to_graph_transformer_input +from gigl.transforms.graph_transformer import ( + PPR_WEIGHT_FEATURE_NAME, + heterodata_to_graph_transformer_input, +) def _get_node_type_positional_encodings( @@ -54,6 +58,25 @@ def _get_node_type_positional_encodings( return torch.cat(pe_parts, dim=-1) +def _build_sinusoidal_sequence_position_table( + max_seq_len: int, + hid_dim: int, +) -> Tensor: + """Build a standard sinusoidal absolute position table.""" + positions = torch.arange(max_seq_len, dtype=torch.float).unsqueeze(1) + div_term = torch.exp( + torch.arange(0, hid_dim, 2, dtype=torch.float) * (-math.log(10000.0) / hid_dim) + ) + + position_table = torch.zeros(max_seq_len, hid_dim, dtype=torch.float) + position_table[:, 0::2] = torch.sin(positions * div_term) + if hid_dim > 1: + position_table[:, 1::2] = torch.cos( + positions * div_term[: position_table[:, 1::2].shape[1]] + ) + return position_table + + # Supported activation functions for FeedForwardNetwork _ACTIVATION_FNS = { "gelu": nn.GELU, @@ -364,7 +387,16 @@ class GraphTransformerEncoder(nn.Module): max_seq_len: Maximum sequence length for the graph-to-sequence transform. Neighborhoods are truncated to this length. hop_distance: Number of hops for neighborhood extraction in the - graph-to-sequence transform. + graph-to-sequence transform when using ``"khop"`` sequence construction. + sequence_construction_method: Sequence builder used to create tokens for + each anchor. ``"khop"`` expands the sampled graph by hop distance, + while ``"ppr"`` consumes outgoing ``"ppr"`` edges sorted by weight. + sequence_positional_encoding_type: Optional sequence-level positional + encoding applied after sequence construction. Supported values are + ``None`` and ``"sinusoidal"``. Lower-cost future extensions could + add learned absolute position embeddings here, while attention-level + options like RoPE or ALiBi would require changes inside the + attention block. dropout_rate: Dropout probability for feed-forward layers. attention_dropout_rate: Dropout probability for attention weights. should_l2_normalize_embedding_layer_output: Whether to L2 normalize @@ -373,14 +405,18 @@ class GraphTransformerEncoder(nn.Module): In ``"concat"`` mode these are concatenated to sequence features. In ``"add"`` mode they are projected to ``hid_dim`` and added to node features before sequence construction. - anchor_based_pe_attr_names: List of relative-encoding attribute names - containing sparse (N x N) matrices for anchor-relative positional - encodings. - These are used as additive attention bias for sequence keys. - pairwise_pe_attr_names: List of relative-encoding attribute names - containing sparse (N x N) matrices for pairwise relative encodings - between sequence nodes. These are used as additive attention bias - and can be combined with anchor-relative bias in the same model. + anchor_based_attention_bias_attr_names: List of anchor-relative feature + names used as additive attention bias for sequence keys. Sparse + graph-level attributes are looked up from ``data`` and the reserved + name ``"ppr_weight"`` resolves to PPR edge weights in PPR mode. + anchor_based_input_attr_names: List of anchor-relative attribute names + used as token-aligned input features. Sparse graph-level attributes + are looked up from ``data`` and ``"ppr_weight"`` resolves to PPR + edge weights in PPR mode. These are projected to ``hid_dim`` and + added to the sequence tokens after sequence construction. + pairwise_attention_bias_attr_names: List of pairwise feature names used + as additive attention bias. These must correspond to sparse + graph-level attributes on ``data``. feature_embedding_layer_dict: Optional ModuleDict mapping node types to feature embedding layers. If provided, these are applied to node features before node projection. (default: None) @@ -436,12 +472,15 @@ def __init__( num_heads: int = 2, max_seq_len: int = 128, hop_distance: int = 2, + sequence_construction_method: Literal["khop", "ppr"] = "khop", + sequence_positional_encoding_type: Optional[str] = None, dropout_rate: float = 0.1, attention_dropout_rate: float = 0.0, should_l2_normalize_embedding_layer_output: bool = False, pe_attr_names: Optional[list[str]] = None, - anchor_based_pe_attr_names: Optional[list[str]] = None, - pairwise_pe_attr_names: Optional[list[str]] = None, + anchor_based_attention_bias_attr_names: Optional[list[str]] = None, + anchor_based_input_attr_names: Optional[list[str]] = None, + pairwise_attention_bias_attr_names: Optional[list[str]] = None, feature_embedding_layer_dict: Optional[nn.ModuleDict] = None, pe_integration_mode: Literal["concat", "add"] = "concat", activation: str = "gelu", @@ -461,15 +500,68 @@ def __init__( self._out_dim = out_dim self._max_seq_len = max_seq_len self._hop_distance = hop_distance + if sequence_construction_method not in {"khop", "ppr"}: + raise ValueError( + "sequence_construction_method must be one of {'khop', 'ppr'}, " + f"got '{sequence_construction_method}'" + ) + if sequence_positional_encoding_type is not None: + sequence_positional_encoding_type = ( + sequence_positional_encoding_type.lower() + ) + if sequence_positional_encoding_type == "none": + sequence_positional_encoding_type = None + if sequence_positional_encoding_type not in {None, "sinusoidal"}: + raise ValueError( + "sequence_positional_encoding_type must be one of " + "{None, 'sinusoidal'}, " + f"got '{sequence_positional_encoding_type}'" + ) + anchor_bias_attr_names = anchor_based_attention_bias_attr_names or [] + anchor_input_attr_names = anchor_based_input_attr_names or [] + pairwise_bias_attr_names = pairwise_attention_bias_attr_names or [] + if PPR_WEIGHT_FEATURE_NAME in pairwise_bias_attr_names: + raise ValueError( + f"'{PPR_WEIGHT_FEATURE_NAME}' is an anchor-relative feature and " + "cannot be used as pairwise attention bias." + ) + if ( + PPR_WEIGHT_FEATURE_NAME in anchor_bias_attr_names + anchor_input_attr_names + and sequence_construction_method != "ppr" + ): + raise ValueError( + "The reserved anchor-relative feature 'ppr_weight' requires " + "sequence_construction_method='ppr'." + ) + self._sequence_construction_method = sequence_construction_method + self._sequence_positional_encoding_type = sequence_positional_encoding_type self._should_l2_normalize_embedding_layer_output = ( should_l2_normalize_embedding_layer_output ) self._pe_attr_names = pe_attr_names - self._anchor_based_pe_attr_names = anchor_based_pe_attr_names - self._pairwise_pe_attr_names = pairwise_pe_attr_names + self._anchor_based_attention_bias_attr_names = ( + anchor_based_attention_bias_attr_names + ) + self._anchor_based_input_attr_names = anchor_based_input_attr_names + self._pairwise_attention_bias_attr_names = pairwise_attention_bias_attr_names self._feature_embedding_layer_dict = feature_embedding_layer_dict self._pe_integration_mode = pe_integration_mode self._num_heads = num_heads + if self._sequence_positional_encoding_type == "sinusoidal": + self.register_buffer( + "_sequence_positional_encoding_table", + _build_sinusoidal_sequence_position_table( + max_seq_len=max_seq_len, + hid_dim=hid_dim, + ), + persistent=False, + ) + else: + self.register_buffer( + "_sequence_positional_encoding_table", + None, + persistent=False, + ) # Per-node-type input projection to hid_dim (like HGT's lin_dict) self._node_projection_dict = nn.ModuleDict( @@ -483,25 +575,31 @@ def __init__( # In "concat" mode: projects [node_features || PE] → hid_dim # In "add" mode: projects PE → hid_dim, then adds to node features self._concat_pe_fusion_projection: Optional[nn.Module] = None - if pe_integration_mode == "concat" and pe_attr_names: + has_node_level_pe = bool(pe_attr_names) + if pe_integration_mode == "concat" and has_node_level_pe: self._concat_pe_fusion_projection = nn.LazyLinear(hid_dim) self._pe_projection: Optional[nn.Module] = None - if pe_integration_mode == "add" and pe_attr_names: + if pe_integration_mode == "add" and has_node_level_pe: self._pe_projection = nn.LazyLinear(hid_dim, bias=False) + self._token_input_projection: Optional[nn.Module] = None + if self._anchor_based_input_attr_names: + self._token_input_projection = nn.LazyLinear(hid_dim, bias=False) + self._anchor_pe_attention_bias_projection: Optional[nn.Linear] = None - if anchor_based_pe_attr_names: + num_anchor_bias_attrs = len(self._anchor_based_attention_bias_attr_names or []) + if num_anchor_bias_attrs > 0: self._anchor_pe_attention_bias_projection = nn.Linear( - len(anchor_based_pe_attr_names), + num_anchor_bias_attrs, num_heads, bias=False, ) self._pairwise_pe_attention_bias_projection: Optional[nn.Linear] = None - if pairwise_pe_attr_names: + if self._pairwise_attention_bias_attr_names: self._pairwise_pe_attention_bias_projection = nn.Linear( - len(pairwise_pe_attr_names), + len(self._pairwise_attention_bias_attr_names), num_heads, bias=False, ) @@ -572,21 +670,29 @@ def forward( projected_x_dict: dict[NodeType, torch.Tensor] = {} for node_type, x in data.x_dict.items(): x_processed = x.to(device) + feature_embedding_layer = None + if ( + self._feature_embedding_layer_dict is not None + and node_type in self._feature_embedding_layer_dict + ): + feature_embedding_layer = self._feature_embedding_layer_dict[node_type] # Apply feature embedding if available for this node type - if self._feature_embedding_layer_dict is not None: - if node_type in self._feature_embedding_layer_dict: - x_processed = self._feature_embedding_layer_dict[node_type]( - x_processed - ) + if feature_embedding_layer is not None: + x_processed = feature_embedding_layer(x_processed) # Project to hid_dim x_projected = self._node_projection_dict[str(node_type)](x_processed) + node_pe_parts = [] if self._pe_attr_names: - node_pe = _get_node_type_positional_encodings( - data=data, - node_type=node_type, - pe_attr_names=self._pe_attr_names, - device=device, + node_pe_parts.append( + _get_node_type_positional_encodings( + data=data, + node_type=node_type, + pe_attr_names=self._pe_attr_names, + device=device, + ) ) + if node_pe_parts: + node_pe = torch.cat(node_pe_parts, dim=-1) if self._pe_integration_mode == "add": if self._pe_projection is None: raise ValueError("PE projection layer is not initialized.") @@ -610,9 +716,17 @@ def forward( projected_data[node_type].batch_size = data[node_type].batch_size for edge_type in data.edge_types: projected_data[edge_type].edge_index = data[edge_type].edge_index + if hasattr(data[edge_type], "edge_attr"): + projected_data[edge_type].edge_attr = data[edge_type].edge_attr # Copy relative-encoding attributes (e.g., hop_distance stored as sparse matrix) - relative_pe_attr_names = set(self._anchor_based_pe_attr_names or []) - relative_pe_attr_names.update(self._pairwise_pe_attr_names or []) + relative_pe_attr_names = { + attr_name + for attr_name in (self._anchor_based_attention_bias_attr_names or []) + if attr_name != PPR_WEIGHT_FEATURE_NAME + } + relative_pe_attr_names.update(self._anchor_based_input_attr_names or []) + relative_pe_attr_names.update(self._pairwise_attention_bias_attr_names or []) + relative_pe_attr_names.discard(PPR_WEIGHT_FEATURE_NAME) if relative_pe_attr_names: for attr_name in sorted(relative_pe_attr_names): if hasattr(data, attr_name): @@ -632,7 +746,7 @@ def forward( ( sequences, valid_mask, - attention_bias_data, + sequence_auxiliary_data, ) = heterodata_to_graph_transformer_input( data=projected_data, batch_size=num_anchor_nodes, @@ -640,8 +754,10 @@ def forward( anchor_node_type=anchor_node_type, anchor_node_ids=anchor_node_ids, hop_distance=self._hop_distance, - anchor_based_pe_attr_names=self._anchor_based_pe_attr_names, - pairwise_pe_attr_names=self._pairwise_pe_attr_names, + sequence_construction_method=self._sequence_construction_method, + anchor_based_attention_bias_attr_names=self._anchor_based_attention_bias_attr_names, + anchor_based_input_attr_names=self._anchor_based_input_attr_names, + pairwise_attention_bias_attr_names=self._pairwise_attention_bias_attr_names, ) # Free memory after sequences are built @@ -653,10 +769,25 @@ def forward( f"got {sequences.size(-1)}." ) + token_input_features = sequence_auxiliary_data.get("token_input") + if token_input_features is not None: + if self._token_input_projection is None: + raise ValueError("Token-input projection is not initialized.") + sequences = sequences + self._token_input_projection( + token_input_features.to(sequences.dtype) + ) + + sequence_positional_encoding = self._get_sequence_positional_encoding( + valid_mask=valid_mask, + sequences=sequences, + ) + if sequence_positional_encoding is not None: + sequences = sequences + sequence_positional_encoding + attn_bias = self._build_attention_bias( valid_mask=valid_mask, sequences=sequences, - attention_bias_data=attention_bias_data, + attention_bias_data=sequence_auxiliary_data, ) embeddings = self._encode_and_readout( @@ -671,6 +802,38 @@ def forward( return embeddings + def _get_sequence_positional_encoding( + self, + valid_mask: Tensor, + sequences: Tensor, + ) -> Optional[Tensor]: + if self._sequence_positional_encoding_type is None: + return None + if self._sequence_positional_encoding_type != "sinusoidal": + raise ValueError( + "Unsupported sequence_positional_encoding_type " + f"'{self._sequence_positional_encoding_type}'." + ) + if self._sequence_positional_encoding_table is None: + raise ValueError("Sequence positional encoding table is not initialized.") + + seq_len = sequences.size(1) + if seq_len > self._sequence_positional_encoding_table.size(0): + raise ValueError( + f"Sequence length {seq_len} exceeds configured max_seq_len " + f"{self._sequence_positional_encoding_table.size(0)}." + ) + + position_encoding = self._sequence_positional_encoding_table[:seq_len] + position_encoding = position_encoding.to( + device=sequences.device, + dtype=sequences.dtype, + ) + position_encoding = position_encoding.unsqueeze(0).expand( + sequences.size(0), -1, -1 + ) + return position_encoding * valid_mask.unsqueeze(-1).to(sequences.dtype) + def _build_attention_bias( self, valid_mask: Tensor, diff --git a/gigl/transforms/graph_transformer.py b/gigl/transforms/graph_transformer.py index 1b4ca7fa4..f99f8b264 100644 --- a/gigl/transforms/graph_transformer.py +++ b/gigl/transforms/graph_transformer.py @@ -1,4 +1,3 @@ -# TODO: support RW sampling, edges from data.ppr_edge, data.ppr_weights """ Transform HeteroData to Graph Transformer sequence input. @@ -52,21 +51,22 @@ ... batch_size=32, ... max_seq_len=128, ... anchor_node_type='user', - ... anchor_based_pe_attr_names=['hop_distance'], # Anchor-based PE (N×N sparse CSR) + ... anchor_based_attention_bias_attr_names=['hop_distance'], ... ) >>> # sequences: (batch_size, max_seq_len, feature_dim) >>> # attention_bias_data['anchor_bias']: (batch_size, max_seq_len, 1) """ -from typing import Optional +from typing import Literal, Optional import torch from torch import Tensor -from torch_geometric.data import HeteroData +from torch_geometric.data import Data, HeteroData from torch_geometric.typing import NodeType from torch_geometric.utils import to_torch_sparse_tensor -AttentionBiasData = dict[str, Optional[Tensor]] +SequenceAuxiliaryData = dict[str, Optional[Tensor]] +PPR_WEIGHT_FEATURE_NAME = "ppr_weight" def heterodata_to_graph_transformer_input( @@ -76,11 +76,13 @@ def heterodata_to_graph_transformer_input( anchor_node_type: NodeType, anchor_node_ids: Optional[Tensor] = None, hop_distance: int = 2, + sequence_construction_method: Literal["khop", "ppr"] = "khop", include_anchor_first: bool = True, padding_value: float = 0.0, - anchor_based_pe_attr_names: Optional[list[str]] = None, - pairwise_pe_attr_names: Optional[list[str]] = None, -) -> tuple[Tensor, Tensor, AttentionBiasData]: + anchor_based_attention_bias_attr_names: Optional[list[str]] = None, + anchor_based_input_attr_names: Optional[list[str]] = None, + pairwise_attention_bias_attr_names: Optional[list[str]] = None, +) -> tuple[Tensor, Tensor, SequenceAuxiliaryData]: """ Transform a HeteroData object to Graph Transformer sequence input. @@ -100,20 +102,27 @@ def heterodata_to_graph_transformer_input( anchor_node_type: The node type of anchor nodes. anchor_node_ids: Optional tensor of local node indices within anchor_node_type to use as anchors. If None, uses first batch_size nodes. (default: None) - hop_distance: Number of hops to consider for neighborhood (default: 2). + hop_distance: Number of hops to consider for neighborhood when + ``sequence_construction_method="khop"``. (default: 2) + sequence_construction_method: Strategy used to build per-anchor sequences. + ``"khop"`` performs the existing k-hop expansion over the sampled graph. + ``"ppr"`` uses outgoing ``(anchor_type, "ppr", neighbor_type)`` edges, + sorted by descending PPR weight from ``edge_attr``. (default: ``"khop"``) include_anchor_first: If True, anchor node is always first in sequence. padding_value: Value to use for padding (default: 0.0). - anchor_based_pe_attr_names: List of relative-encoding attribute names - containing sparse (N x N) matrices for anchor-relative positional - encodings. - For each node in the sequence, the value PE[anchor_idx, node_idx] is - looked up and returned as attention-bias features. - Examples: ['hop_distance'] (from AddHeteroHopDistanceEncoding) - If None, no anchor-based PEs are attached. (default: None) - pairwise_pe_attr_names: List of relative-encoding attribute names - containing sparse (N x N) matrices for pairwise relative encodings. - For each pair of sequence nodes (i, j), the value PE[node_i, node_j] - is looked up and returned as attention-bias features. (default: None) + anchor_based_attention_bias_attr_names: List of anchor-relative feature + names used as attention bias. Sparse graph-level attributes are + looked up from ``data`` and the reserved name ``"ppr_weight"`` + resolves to PPR edge weights in PPR sequence mode. + Example: ['hop_distance', 'ppr_weight']. + anchor_based_input_attr_names: List of anchor-relative attribute names + returned as token-aligned model-input features. Sparse graph-level + attributes are looked up from ``data`` and ``"ppr_weight"`` resolves + to PPR edge weights in PPR sequence mode. + Example: ['hop_distance', 'ppr_weight']. + pairwise_attention_bias_attr_names: List of pairwise feature names used + as attention bias. These must correspond to sparse graph-level + attributes on ``data``. Example: ['pairwise_distance']. Returns: (sequences, valid_mask, attention_bias_data), where: @@ -121,10 +130,13 @@ def heterodata_to_graph_transformer_input( taken directly from ``data[node_type].x`` in homogeneous order. valid_mask: (batch_size, max_seq_len) bool tensor indicating which sequence positions correspond to real nodes. - attention_bias_data: dictionary of raw attention-bias features with: + sequence_auxiliary_data: dictionary of raw token-aligned and + attention-bias features with: ``"anchor_bias"`` shaped ``(batch, seq, num_anchor_attrs)`` or None ``"pairwise_bias"`` shaped ``(batch, seq, seq, num_pairwise_attrs)`` or None + ``"token_input"`` shaped + ``(batch, seq, num_token_input_attrs)`` or None Raises: ValueError: If node types have different feature dimensions. @@ -160,73 +172,115 @@ def heterodata_to_graph_transformer_input( f"Found different dimensions: {feature_dims}" ) + anchor_bias_attr_names = anchor_based_attention_bias_attr_names or [] + anchor_input_attr_names = anchor_based_input_attr_names or [] + pairwise_bias_attr_names = pairwise_attention_bias_attr_names or [] + + if PPR_WEIGHT_FEATURE_NAME in pairwise_bias_attr_names: + raise ValueError( + f"'{PPR_WEIGHT_FEATURE_NAME}' is an anchor-relative feature and cannot " + "be used as pairwise attention bias." + ) + + if ( + PPR_WEIGHT_FEATURE_NAME in anchor_bias_attr_names + anchor_input_attr_names + and sequence_construction_method != "ppr" + ): + raise ValueError( + "The reserved anchor-relative feature 'ppr_weight' requires " + "sequence_construction_method='ppr'." + ) + + if sequence_construction_method == "ppr": + _validate_ppr_sequence_input(data) + device = data[anchor_node_type].x.device # Convert to homogeneous for easier neighborhood extraction homo_data = data.to_homogeneous() homo_x = homo_data.x # (total_nodes, feature_dim) - homo_edge_index = homo_data.edge_index # (2, num_edges) num_nodes = homo_data.num_nodes - # Get node type to index mapping (sorted alphabetically) - sorted_node_types = sorted(data.node_types) + # Match the node-type ordering used by to_homogeneous() so homogeneous + # indices line up with homo_x / homo_edge_index. + node_type_order = list(getattr(homo_data, "_node_type_names", data.node_types)) + node_type_offsets = _get_node_type_offsets( + data=data, node_type_order=node_type_order + ) # Find offset for anchor_node_type in homogeneous graph - # Nodes are ordered by node_type (alphabetically), then by original index - offset = 0 - for nt in sorted_node_types: - if nt == anchor_node_type: - break - offset += data[nt].num_nodes + # Nodes are ordered by the homogeneous node-type order, then by original index. + offset = node_type_offsets[anchor_node_type] # Determine anchor indices in homogeneous graph if anchor_node_ids is not None: # Use provided local indices, convert to homogeneous indices - anchor_indices = offset + anchor_node_ids.to(device) + anchor_local_indices = anchor_node_ids.to(device) else: # Default: first batch_size nodes of anchor_node_type - anchor_indices = torch.arange(offset, offset + batch_size, device=device) + anchor_local_indices = torch.arange(batch_size, device=device) + anchor_indices = offset + anchor_local_indices + + ppr_weight_sequences: Optional[Tensor] = None + if sequence_construction_method == "khop": + homo_edge_index = homo_data.edge_index # (2, num_edges) + # Use sparse matrix operations for efficient k-hop neighbor extraction + # Returns: (batch_size, num_nodes) sparse matrix where non-zero entries are reachable + reachable = _get_k_hop_neighbors_sparse( + anchor_indices=anchor_indices, + edge_index=homo_edge_index, + num_nodes=num_nodes, + k=hop_distance, + device=device, + ) + node_index_sequences, valid_mask = _build_sequence_layout_from_sparse_neighbors( + reachable=reachable, + anchor_indices=anchor_indices, + max_seq_len=max_seq_len, + include_anchor_first=include_anchor_first, + device=device, + ) + elif sequence_construction_method == "ppr": + ( + node_index_sequences, + valid_mask, + ppr_weight_sequences, + ) = _build_sequence_layout_from_ppr_edges( + homo_data=homo_data, + anchor_indices=anchor_indices, + max_seq_len=max_seq_len, + include_anchor_first=include_anchor_first, + num_nodes=num_nodes, + device=device, + return_edge_weights=( + PPR_WEIGHT_FEATURE_NAME + in anchor_bias_attr_names + anchor_input_attr_names + ), + ) + else: + raise ValueError( + "sequence_construction_method must be one of ['khop', 'ppr'], " + f"got '{sequence_construction_method}'." + ) - # Use sparse matrix operations for efficient k-hop neighbor extraction - # Returns: (batch_size, num_nodes) sparse matrix where non-zero entries are reachable - reachable = _get_k_hop_neighbors_sparse( - anchor_indices=anchor_indices, - edge_index=homo_edge_index, - num_nodes=num_nodes, - k=hop_distance, - device=device, + anchor_matrix_attr_names = list( + { + attr_name + for attr_name in (anchor_bias_attr_names + anchor_input_attr_names) + if attr_name != PPR_WEIGHT_FEATURE_NAME + } + ) + anchor_based_matrices = _get_sparse_feature_matrices( + data=data, + attr_names=anchor_matrix_attr_names, + missing_attr_error_prefix="Anchor-based attribute", ) - # Get anchor-based PE matrices if specified - anchor_based_pe_matrices = [] - if anchor_based_pe_attr_names: - for attr_name in anchor_based_pe_attr_names: - if hasattr(data, attr_name): - anchor_based_pe_matrices.append(getattr(data, attr_name)) - else: - raise ValueError( - f"Anchor-based PE attribute '{attr_name}' not found in data. " - f"Make sure to apply the corresponding transform first." - ) - - pairwise_pe_matrices = [] - if pairwise_pe_attr_names: - for attr_name in pairwise_pe_attr_names: - if hasattr(data, attr_name): - pairwise_pe_matrices.append(getattr(data, attr_name)) - else: - raise ValueError( - f"Pairwise PE attribute '{attr_name}' not found in data. " - f"Make sure to apply the corresponding transform first." - ) - - node_index_sequences, valid_mask = _build_sequence_layout_from_sparse_neighbors( - reachable=reachable, - anchor_indices=anchor_indices, - max_seq_len=max_seq_len, - include_anchor_first=include_anchor_first, - device=device, + pairwise_pe_matrices = _get_sparse_feature_matrices( + data=data, + attr_names=pairwise_bias_attr_names, + missing_attr_error_prefix="Pairwise PE attribute", ) node_feature_sequences = _gather_sequences_from_node_indices( @@ -240,7 +294,7 @@ def heterodata_to_graph_transformer_input( anchor_indices=anchor_indices, node_index_sequences=node_index_sequences, valid_mask=valid_mask, - csr_matrices=anchor_based_pe_matrices if anchor_based_pe_matrices else None, + csr_matrices=anchor_based_matrices if anchor_based_matrices else None, device=device, ) @@ -251,16 +305,118 @@ def heterodata_to_graph_transformer_input( device=device, ) + anchor_bias_features = _compose_anchor_feature_tensor( + anchor_relative_feature_sequences=anchor_relative_feature_sequences, + available_anchor_attr_names=anchor_matrix_attr_names, + requested_anchor_attr_names=anchor_bias_attr_names, + ppr_weight_sequences=ppr_weight_sequences, + ) + token_input_features = _compose_anchor_feature_tensor( + anchor_relative_feature_sequences=anchor_relative_feature_sequences, + available_anchor_attr_names=anchor_matrix_attr_names, + requested_anchor_attr_names=anchor_input_attr_names, + ppr_weight_sequences=ppr_weight_sequences, + ) + return ( node_feature_sequences, valid_mask, { - "anchor_bias": anchor_relative_feature_sequences, + "anchor_bias": anchor_bias_features, "pairwise_bias": pairwise_feature_sequences, + "token_input": token_input_features, }, ) +def _get_node_type_offsets( + data: HeteroData, + node_type_order: list[NodeType], +) -> dict[NodeType, int]: + offsets: dict[NodeType, int] = {} + offset = 0 + for node_type in node_type_order: + offsets[node_type] = offset + offset += data[node_type].num_nodes + return offsets + + +def _validate_ppr_sequence_input(data: HeteroData) -> None: + if not data.edge_types: + raise ValueError( + "sequence_construction_method='ppr' requires at least one PPR edge type." + ) + + if any(edge_type[1] != "ppr" for edge_type in data.edge_types): + raise ValueError( + "sequence_construction_method='ppr' expects the hetero batch to contain " + f"only PPR edges, got edge types: {data.edge_types}." + ) + + for edge_type in data.edge_types: + edge_store = data[edge_type] + if not hasattr(edge_store, "edge_attr") or edge_store.edge_attr is None: + raise ValueError( + "sequence_construction_method='ppr' requires every PPR edge type to " + f"have edge_attr weights, but {edge_type} is missing them." + ) + + +def _get_sparse_feature_matrices( + data: HeteroData, + attr_names: Optional[list[str]], + missing_attr_error_prefix: str, +) -> list[Tensor]: + matrices: list[Tensor] = [] + for attr_name in attr_names or []: + if not hasattr(data, attr_name): + raise ValueError( + f"{missing_attr_error_prefix} '{attr_name}' not found in data. " + "Make sure to apply the corresponding transform first." + ) + matrices.append(getattr(data, attr_name)) + return matrices + + +def _compose_anchor_feature_tensor( + anchor_relative_feature_sequences: Optional[Tensor], + available_anchor_attr_names: list[str], + requested_anchor_attr_names: list[str], + ppr_weight_sequences: Optional[Tensor], +) -> Optional[Tensor]: + if not requested_anchor_attr_names: + return None + + feature_parts: list[Tensor] = [] + feature_index_by_name = { + attr_name: idx for idx, attr_name in enumerate(available_anchor_attr_names) + } + + for attr_name in requested_anchor_attr_names: + if attr_name == PPR_WEIGHT_FEATURE_NAME: + if ppr_weight_sequences is None: + raise ValueError( + f"Requested '{PPR_WEIGHT_FEATURE_NAME}' but it was not computed." + ) + feature_parts.append(ppr_weight_sequences) + continue + + if anchor_relative_feature_sequences is None: + raise ValueError( + "Anchor-relative features were requested but not computed." + ) + if attr_name not in feature_index_by_name: + raise ValueError( + f"Anchor-relative feature '{attr_name}' was requested but not found." + ) + feature_idx = feature_index_by_name[attr_name] + feature_parts.append( + anchor_relative_feature_sequences[..., feature_idx : feature_idx + 1] + ) + + return torch.cat(feature_parts, dim=-1) + + def _build_sequence_layout_from_sparse_neighbors( reachable: Tensor, anchor_indices: Tensor, @@ -357,6 +513,139 @@ def _build_sequence_layout_from_sparse_neighbors( return node_index_sequences, valid_mask +def _build_sequence_layout_from_ppr_edges( + homo_data: Data, + anchor_indices: Tensor, + max_seq_len: int, + include_anchor_first: bool, + num_nodes: int, + device: torch.device, + return_edge_weights: bool = False, +) -> tuple[Tensor, Tensor, Optional[Tensor]]: + """Build sequences directly from outgoing PPR edges for each anchor. + + The sequence order is: + 1. Anchor node first, when ``include_anchor_first`` is True. + 2. Destination nodes reachable by outgoing ``"ppr"`` edges from that anchor, + sorted by descending PPR weight. + """ + batch_size = anchor_indices.size(0) + node_index_sequences = torch.full( + (batch_size, max_seq_len), + fill_value=-1, + dtype=torch.long, + device=device, + ) + valid_mask = torch.zeros( + (batch_size, max_seq_len), + dtype=torch.bool, + device=device, + ) + ppr_weight_sequences = None + if return_edge_weights: + ppr_weight_sequences = torch.zeros( + (batch_size, max_seq_len, 1), + dtype=torch.float, + device=device, + ) + + if include_anchor_first and max_seq_len > 0: + node_index_sequences[:, 0] = anchor_indices + valid_mask[:, 0] = True + start_pos = 1 + else: + start_pos = 0 + + if start_pos >= max_seq_len: + return node_index_sequences, valid_mask, ppr_weight_sequences + + if not hasattr(homo_data, "edge_attr") or homo_data.edge_attr is None: + raise ValueError( + "sequence_construction_method='ppr' requires homogeneous edge_attr weights." + ) + + edge_weights = homo_data.edge_attr + if edge_weights.dim() == 2: + if edge_weights.size(1) != 1: + raise ValueError( + "PPR edge weights must be 1D or shape [N, 1], " + f"got {tuple(edge_weights.shape)}." + ) + edge_weights = edge_weights.squeeze(1) + elif edge_weights.dim() != 1: + raise ValueError( + "PPR edge weights must be 1D or shape [N, 1], " + f"got {tuple(edge_weights.shape)}." + ) + + anchor_batch_index_by_homo_idx = torch.full( + (num_nodes,), + fill_value=-1, + dtype=torch.long, + device=device, + ) + anchor_batch_index_by_homo_idx[anchor_indices] = torch.arange( + batch_size, device=device + ) + + src_idx = homo_data.edge_index[0] + dst_idx = homo_data.edge_index[1] + anchor_batch_idx = anchor_batch_index_by_homo_idx[src_idx] + keep = anchor_batch_idx >= 0 + if not keep.any(): + return node_index_sequences, valid_mask, ppr_weight_sequences + + all_anchor_batch_idx = anchor_batch_idx[keep] + all_dst_idx = dst_idx[keep] + all_weights = edge_weights[keep] + + if include_anchor_first: + keep = all_dst_idx != anchor_indices[all_anchor_batch_idx] + if not keep.any(): + return node_index_sequences, valid_mask, ppr_weight_sequences + all_anchor_batch_idx = all_anchor_batch_idx[keep] + all_dst_idx = all_dst_idx[keep] + all_weights = all_weights[keep] + + # Flattened COO edges can be laid out in one pass by sorting first on weight + # and then stably on anchor batch id, which preserves descending-weight order + # within each anchor group without a Python loop. + weight_order = torch.argsort(all_weights, descending=True, stable=True) + all_anchor_batch_idx = all_anchor_batch_idx[weight_order] + all_dst_idx = all_dst_idx[weight_order] + all_weights = all_weights[weight_order] + + batch_order = torch.argsort(all_anchor_batch_idx, stable=True) + sorted_batch_idx = all_anchor_batch_idx[batch_order] + sorted_dst_idx = all_dst_idx[batch_order] + sorted_weights = all_weights[batch_order] + + n = sorted_batch_idx.size(0) + is_group_start = torch.zeros(n, dtype=torch.long, device=device) + is_group_start[0] = 1 + if n > 1: + is_group_start[1:] = (sorted_batch_idx[1:] != sorted_batch_idx[:-1]).long() + + group_id = is_group_start.cumsum(0) - 1 + group_starts = torch.nonzero(is_group_start, as_tuple=True)[0] + positions = torch.arange(n, device=device) - group_starts[group_id] + start_pos + + valid = positions < max_seq_len + valid_batch_idx = sorted_batch_idx[valid] + valid_positions = positions[valid] + valid_dst_idx = sorted_dst_idx[valid] + valid_weights = sorted_weights[valid] + + node_index_sequences[valid_batch_idx, valid_positions] = valid_dst_idx + valid_mask[valid_batch_idx, valid_positions] = True + if ppr_weight_sequences is not None: + ppr_weight_sequences[ + valid_batch_idx, valid_positions, 0 + ] = valid_weights.float() + + return node_index_sequences, valid_mask, ppr_weight_sequences + + def _gather_sequences_from_node_indices( node_index_sequences: Tensor, node_features: Tensor, diff --git a/tests/unit/src/common/models/graph_transformer/graph_transformer_test.py b/tests/unit/src/common/models/graph_transformer/graph_transformer_test.py index 3a3c558bd..103237c72 100644 --- a/tests/unit/src/common/models/graph_transformer/graph_transformer_test.py +++ b/tests/unit/src/common/models/graph_transformer/graph_transformer_test.py @@ -257,6 +257,20 @@ def _create_user_graph_with_pe() -> HeteroData: return data +def _create_user_graph_with_ppr_edges() -> HeteroData: + data = HeteroData() + + data["user"].x = torch.tensor( + [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0]] + ) + data["user", "ppr", "user"].edge_index = torch.tensor([[0, 0, 1], [1, 2, 2]]) + data["user", "ppr", "user"].edge_attr = torch.tensor([0.9, 0.4, 0.7]) + hop_distance = torch.tensor([[0.0, 1.0, 2.0], [1.0, 0.0, 1.0], [2.0, 1.0, 0.0]]) + data.hop_distance = hop_distance.to_sparse_csr() + + return data + + class TestGraphTransformerEncoderPEModes(TestCase): def setUp(self) -> None: self._node_type = NodeType("user") @@ -328,8 +342,8 @@ def test_forward_accepts_pairwise_attention_bias(self) -> None: encoder = self._create_encoder( pe_attr_names=["random_walk_pe"], - anchor_based_pe_attr_names=["hop_distance"], - pairwise_pe_attr_names=["pairwise_distance"], + anchor_based_attention_bias_attr_names=["hop_distance"], + pairwise_attention_bias_attr_names=["pairwise_distance"], pe_integration_mode="add", ) encoder.eval() @@ -365,8 +379,8 @@ def test_concat_mode_infers_sequence_width_without_explicit_pe_dim(self) -> None def test_attention_bias_features_are_projected_per_head(self) -> None: encoder = self._create_encoder( - anchor_based_pe_attr_names=["hop_distance"], - pairwise_pe_attr_names=["pairwise_distance"], + anchor_based_attention_bias_attr_names=["hop_distance"], + pairwise_attention_bias_attr_names=["pairwise_distance"], ) assert encoder._anchor_pe_attention_bias_projection is not None @@ -403,6 +417,189 @@ def test_attention_bias_features_are_projected_per_head(self) -> None: self.assertEqual(attn_bias[0, 0, 2, 2].item(), 27.0) self.assertEqual(attn_bias[0, 1, 2, 2].item(), 38.0) + def test_attention_bias_supports_anchor_relative_attrs_and_ppr_weights( + self, + ) -> None: + encoder = self._create_encoder( + edge_type_to_feat_dim_map={ + EdgeType(self._node_type, Relation("ppr"), self._node_type): 0 + }, + sequence_construction_method="ppr", + anchor_based_attention_bias_attr_names=["hop_distance", "ppr_weight"], + ) + + assert encoder._anchor_pe_attention_bias_projection is not None + + with torch.no_grad(): + encoder._anchor_pe_attention_bias_projection.weight.copy_( + torch.tensor([[1.0, 10.0], [2.0, 20.0]]) + ) + + attn_bias = encoder._build_attention_bias( + valid_mask=torch.ones((1, 3), dtype=torch.bool), + sequences=torch.zeros((1, 3, 8), dtype=torch.float), + attention_bias_data={ + "anchor_bias": torch.tensor( + [[[1.0, 0.5], [2.0, 0.25], [3.0, 0.125]]] + ), + "pairwise_bias": None, + "token_input": None, + }, + ) + + self.assertEqual(attn_bias.shape, (1, 2, 3, 3)) + self.assertEqual(attn_bias[0, 0, 0, 1].item(), 4.5) + self.assertEqual(attn_bias[0, 1, 0, 1].item(), 9.0) + self.assertEqual(attn_bias[0, 0, 2, 2].item(), 4.25) + self.assertEqual(attn_bias[0, 1, 2, 2].item(), 8.5) + + def test_sinusoidal_sequence_positional_encoding_masks_padding(self) -> None: + encoder = self._create_encoder( + sequence_positional_encoding_type="sinusoidal", + ) + + sequence_positional_encoding = encoder._get_sequence_positional_encoding( + valid_mask=torch.tensor([[True, True, False, False]]), + sequences=torch.zeros((1, 4, 8), dtype=torch.float), + ) + + assert sequence_positional_encoding is not None + expected_position_zero = torch.tensor( + [0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0], + dtype=torch.float, + ) + self.assertEqual(sequence_positional_encoding.shape, (1, 4, 8)) + self.assertTrue( + torch.allclose(sequence_positional_encoding[0, 0], expected_position_zero) + ) + self.assertFalse( + torch.allclose( + sequence_positional_encoding[0, 1], + torch.zeros(8, dtype=torch.float), + ) + ) + self.assertTrue( + torch.allclose( + sequence_positional_encoding[0, 2:], + torch.zeros((2, 8), dtype=torch.float), + ) + ) + + def test_forward_supports_ppr_sequence_construction(self) -> None: + data = _create_user_graph_with_ppr_edges() + + encoder = self._create_encoder( + edge_type_to_feat_dim_map={ + EdgeType(self._node_type, Relation("ppr"), self._node_type): 0 + }, + sequence_construction_method="ppr", + ) + encoder.eval() + + with torch.no_grad(): + embeddings = encoder( + data=data, + anchor_node_type=self._node_type, + device=self._device, + ) + + self.assertEqual(embeddings.shape, (3, 6)) + self.assertFalse(torch.isnan(embeddings).any()) + + def test_forward_supports_sinusoidal_sequence_position_encoding_in_ppr_mode( + self, + ) -> None: + data = _create_user_graph_with_ppr_edges() + encoder = self._create_encoder( + edge_type_to_feat_dim_map={ + EdgeType(self._node_type, Relation("ppr"), self._node_type): 0 + }, + sequence_construction_method="ppr", + sequence_positional_encoding_type="sinusoidal", + anchor_based_attention_bias_attr_names=["hop_distance", "ppr_weight"], + anchor_based_input_attr_names=["hop_distance", "ppr_weight"], + ) + encoder.eval() + + with torch.no_grad(): + _ = encoder( + data=data, + anchor_node_type=self._node_type, + device=self._device, + ) + assert encoder._sequence_positional_encoding_table is not None + original_position_table = ( + encoder._sequence_positional_encoding_table.detach().clone() + ) + + embeddings_with_position_encoding = encoder( + data=data, + anchor_node_type=self._node_type, + device=self._device, + ) + encoder._sequence_positional_encoding_table.zero_() + embeddings_without_position_encoding = encoder( + data=data, + anchor_node_type=self._node_type, + device=self._device, + ) + encoder._sequence_positional_encoding_table.copy_(original_position_table) + + self.assertEqual(embeddings_with_position_encoding.shape, (3, 6)) + self.assertFalse(torch.isnan(embeddings_with_position_encoding).any()) + self.assertFalse( + torch.allclose( + embeddings_with_position_encoding, + embeddings_without_position_encoding, + ) + ) + + def test_forward_supports_anchor_relative_and_ppr_token_input_features( + self, + ) -> None: + data = _create_user_graph_with_ppr_edges() + ppr_edge_type = EdgeType(self._node_type, Relation("ppr"), self._node_type) + + base_encoder = self._create_encoder( + edge_type_to_feat_dim_map={ppr_edge_type: 0}, + sequence_construction_method="ppr", + ) + augmented_encoder = self._create_encoder( + edge_type_to_feat_dim_map={ppr_edge_type: 0}, + sequence_construction_method="ppr", + anchor_based_input_attr_names=["hop_distance", "ppr_weight"], + ) + augmented_encoder.load_state_dict(base_encoder.state_dict(), strict=False) + + base_encoder.eval() + augmented_encoder.eval() + + with torch.no_grad(): + _ = augmented_encoder( + data=data, + anchor_node_type=self._node_type, + device=self._device, + ) + assert augmented_encoder._token_input_projection is not None + assert isinstance(augmented_encoder._token_input_projection, nn.Linear) + augmented_encoder._token_input_projection.weight.data.zero_() + + base_embeddings = base_encoder( + data=data, + anchor_node_type=self._node_type, + device=self._device, + ) + augmented_embeddings = augmented_encoder( + data=data, + anchor_node_type=self._node_type, + device=self._device, + ) + + self.assertEqual(augmented_embeddings.shape, (3, 6)) + self.assertTrue( + torch.allclose(base_embeddings, augmented_embeddings, atol=1e-6) + ) + class TestFeedForwardNetwork(TestCase): """Tests for FeedForwardNetwork with various activations.""" diff --git a/tests/unit/transforms/graph_transformer_test.py b/tests/unit/transforms/graph_transformer_test.py index 14382d680..fffac1805 100644 --- a/tests/unit/transforms/graph_transformer_test.py +++ b/tests/unit/transforms/graph_transformer_test.py @@ -68,6 +68,60 @@ def create_larger_hetero_data(num_users: int = 10, num_items: int = 5) -> Hetero return data +def create_ppr_sequence_hetero_data() -> HeteroData: + """Create a graph with explicit PPR edges for sequence-construction tests.""" + data = HeteroData() + + data["user"].x = torch.tensor([[10.0, 0.0], [11.0, 0.0]]) + data["item"].x = torch.tensor([[0.0, 20.0], [0.0, 21.0]]) + + data["user", "ppr", "item"].edge_index = torch.tensor( + [ + [0, 0, 1], + [1, 0, 0], + ] + ) + data["user", "ppr", "item"].edge_attr = torch.tensor([0.9, 0.6, 0.8]) + + data["user", "ppr", "user"].edge_index = torch.tensor( + [ + [0, 1], + [1, 0], + ] + ) + data["user", "ppr", "user"].edge_attr = torch.tensor([0.4, 0.3]) + + homo_data = data.to_homogeneous() + node_type_order = list(getattr(homo_data, "_node_type_names", data.node_types)) + offsets = {} + offset = 0 + for node_type in node_type_order: + offsets[node_type] = offset + offset += data[node_type].num_nodes + + total_nodes = homo_data.num_nodes + hop_distance = torch.zeros((total_nodes, total_nodes), dtype=torch.float) + + user0_idx = offsets["user"] + 0 + user1_idx = offsets["user"] + 1 + item0_idx = offsets["item"] + 0 + item1_idx = offsets["item"] + 1 + + hop_distance[user0_idx, user0_idx] = 0.0 + hop_distance[user0_idx, user1_idx] = 1.0 + hop_distance[user0_idx, item0_idx] = 2.0 + hop_distance[user0_idx, item1_idx] = 3.0 + + hop_distance[user1_idx, user0_idx] = 1.0 + hop_distance[user1_idx, user1_idx] = 0.0 + hop_distance[user1_idx, item0_idx] = 4.0 + hop_distance[user1_idx, item1_idx] = 5.0 + + data.hop_distance = hop_distance.to_sparse_csr() + + return data + + class TestGetKHopNeighborsSparse(TestCase): """Tests for _get_k_hop_neighbors_sparse helper function.""" @@ -232,8 +286,13 @@ def test_anchor_first(self): # Get anchor node feature homo_data = data.to_homogeneous() - # 'item' comes before 'user' alphabetically, so user offset = num_items = 2 - anchor_feature = homo_data.x[2] # First user node + node_type_order = list(getattr(homo_data, "_node_type_names", data.node_types)) + user_offset = 0 + for node_type in node_type_order: + if node_type == "user": + break + user_offset += data[node_type].num_nodes + anchor_feature = homo_data.x[user_offset] # First user node sequences, _, _ = heterodata_to_graph_transformer_input( data=data, @@ -327,6 +386,100 @@ def test_custom_padding_value(self): expected_padding = torch.full_like(padding_features, -1.0) self.assertTrue(torch.allclose(padding_features, expected_padding)) + def test_ppr_sequence_construction_sorts_tokens_by_weight(self): + """Test that PPR mode uses outgoing PPR edges ordered by descending weight.""" + data = create_ppr_sequence_hetero_data() + + sequences, valid_mask, _ = heterodata_to_graph_transformer_input( + data=data, + batch_size=2, + max_seq_len=4, + anchor_node_type="user", + sequence_construction_method="ppr", + ) + + expected_anchor_0 = torch.tensor( + [ + [10.0, 0.0], # anchor user0 + [0.0, 21.0], # item1, weight 0.9 + [0.0, 20.0], # item0, weight 0.6 + [11.0, 0.0], # user1, weight 0.4 + ] + ) + expected_anchor_1 = torch.tensor( + [ + [11.0, 0.0], # anchor user1 + [0.0, 20.0], # item0, weight 0.8 + [10.0, 0.0], # user0, weight 0.3 + [0.0, 0.0], # padding + ] + ) + + self.assertTrue(torch.allclose(sequences[0], expected_anchor_0)) + self.assertTrue(torch.allclose(sequences[1], expected_anchor_1)) + self.assertTrue( + torch.equal(valid_mask[0], torch.tensor([True, True, True, True])) + ) + self.assertTrue( + torch.equal(valid_mask[1], torch.tensor([True, True, True, False])) + ) + + def test_ppr_sequence_construction_requires_only_ppr_relations(self): + data = create_simple_hetero_data() + + with self.assertRaisesRegex(ValueError, "contain only PPR edges"): + heterodata_to_graph_transformer_input( + data=data, + batch_size=1, + max_seq_len=4, + anchor_node_type="user", + sequence_construction_method="ppr", + ) + + def test_ppr_sequence_can_return_token_input_and_attention_bias_features(self): + data = create_ppr_sequence_hetero_data() + + _, valid_mask, sequence_auxiliary_data = heterodata_to_graph_transformer_input( + data=data, + batch_size=2, + max_seq_len=4, + anchor_node_type="user", + sequence_construction_method="ppr", + anchor_based_attention_bias_attr_names=["hop_distance", "ppr_weight"], + anchor_based_input_attr_names=["hop_distance", "ppr_weight"], + ) + + anchor_bias = sequence_auxiliary_data["anchor_bias"] + token_input = sequence_auxiliary_data["token_input"] + assert anchor_bias is not None + assert token_input is not None + + expected_anchor_0 = torch.tensor( + [ + [0.0, 0.0], + [3.0, 0.9], + [2.0, 0.6], + [1.0, 0.4], + ] + ) + expected_anchor_1 = torch.tensor( + [ + [0.0, 0.0], + [4.0, 0.8], + [1.0, 0.3], + [0.0, 0.0], + ] + ) + + self.assertEqual(anchor_bias.shape, (2, 4, 2)) + self.assertEqual(token_input.shape, (2, 4, 2)) + self.assertTrue(torch.allclose(anchor_bias[0], expected_anchor_0)) + self.assertTrue(torch.allclose(anchor_bias[1], expected_anchor_1)) + self.assertTrue(torch.allclose(token_input, anchor_bias)) + self.assertTrue( + torch.equal(valid_mask[1], torch.tensor([True, True, True, False])) + ) + class TestPyTorchTransformerIntegration(TestCase): """Tests for integration with PyTorch TransformerEncoderLayer.""" @@ -620,7 +773,7 @@ def test_transform_returns_base_sequences_and_anchor_relative_bias(self) -> None max_seq_len=4, anchor_node_type="user", hop_distance=2, - anchor_based_pe_attr_names=["hop_distance"], + anchor_based_attention_bias_attr_names=["hop_distance"], ) self.assertEqual(sequences.shape, (1, 4, 4)) @@ -645,8 +798,8 @@ def test_attention_bias_outputs_include_valid_mask_and_relative_features( max_seq_len=4, anchor_node_type="user", hop_distance=2, - anchor_based_pe_attr_names=["hop_distance"], - pairwise_pe_attr_names=["pairwise_distance"], + anchor_based_attention_bias_attr_names=["hop_distance"], + pairwise_attention_bias_attr_names=["pairwise_distance"], ) self.assertEqual(sequences.shape, (1, 4, 4)) From b5b802726ffa51fa90efdb1be2fd8ced45105405 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 19:51:55 +0000 Subject: [PATCH 004/148] Auto-build C++ extensions in post_install; auto-add LLVM to PATH on Mac --- Makefile | 2 +- gigl/scripts/post_install.py | 40 +++++++++++++++++++--------- requirements/install_cpp_deps.sh | 22 ++++++++------- scripts/generate_compile_commands.py | 26 +++++++++--------- 4 files changed, 56 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 11d8ba848..f13be1c18 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ format: format_py format_scala format_md format_cpp type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs -lint_cpp: build_cpp_extensions +lint_cpp: uv run python scripts/generate_compile_commands.py clang-tidy -p build/compile_commands.json $(CPP_SOURCES) diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index cd13c4b0b..918d62fb5 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -3,8 +3,9 @@ Once GiGL is installed w/ `pip install gigl`, this script can be executed by running: `gigl-post-install` -This script is used to install the dependencies for GIGL. -- Currently, it installs GLT by running install_glt.sh. +This script is used to install the dependencies for GIGL: +- Installs GLT by running install_glt.sh. +- Builds pybind11 C++ extensions in-place so they are importable without a separate build step. """ import subprocess @@ -38,24 +39,19 @@ def main(): """Main entry point for the post-install script.""" print("Running GIGL post-install script...") - # Get the directory where this script is located script_dir = Path(__file__).parent + repo_root = script_dir.parent.parent - # Path to the install_glt.sh script + # Step 1: Install GLT install_glt_script = script_dir / "install_glt.sh" - if not install_glt_script.exists(): print(f"Error: install_glt.sh not found at {install_glt_script}") sys.exit(1) - cmd = f"bash {install_glt_script}" - try: - print(f"Executing {cmd}...") - result = run_command_and_stream_stdout(cmd) - print("Post-install script finished running, with return code: ", result) - return result - + print(f"Executing bash {install_glt_script}...") + result = run_command_and_stream_stdout(f"bash {install_glt_script}") + print("GLT install finished with return code:", result) except subprocess.CalledProcessError as e: print(f"Error running install_glt.sh: {e}") sys.exit(1) @@ -63,6 +59,26 @@ def main(): print(f"Unexpected error: {e}") sys.exit(1) + # Step 2: Build pybind11 C++ extensions in-place so they are importable + # without requiring a separate `make build_cpp_extensions` call. + setup_py = repo_root / "setup.py" + if setup_py.exists(): + cmd = f"cd {repo_root} && {sys.executable} setup.py build_ext --inplace" + try: + print("Building C++ extensions...") + result = run_command_and_stream_stdout(cmd) + print("C++ extension build finished with return code:", result) + except subprocess.CalledProcessError as e: + print(f"Error building C++ extensions: {e}") + sys.exit(1) + except Exception as e: + print(f"Unexpected error building C++ extensions: {e}") + sys.exit(1) + else: + print(f"Warning: {setup_py} not found, skipping C++ extension build") + + return result + if __name__ == "__main__": main() diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 9a3aacbd7..7675a0396 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -18,16 +18,20 @@ is_running_on_mac() { if is_running_on_mac; then # `brew install llvm` provides clang-format and clang-tidy. # Homebrew does not add llvm to PATH by default to avoid shadowing Apple's - # clang, so we print an instruction for the developer to do it manually. + # clang, so we add it ourselves. brew install llvm cmake - LLVM_PREFIX=$(brew --prefix llvm) - set +x - echo "" - echo "NOTE: Add the LLVM bin directory to your PATH to use clang-format and clang-tidy:" - echo " export PATH=\"${LLVM_PREFIX}/bin:\$PATH\"" - echo " (Add this to your ~/.zshrc or ~/.bashrc to make it permanent.)" - echo "" - set -x + LLVM_BIN="$(brew --prefix llvm)/bin" + + # Append to any shell rc files that exist and don't already include it. + for rc_file in ~/.zshrc ~/.bashrc; do + if [ -f "$rc_file" ] && ! grep -qF "$LLVM_BIN" "$rc_file"; then + printf '\n# Added by GiGL install_cpp_deps.sh\nexport PATH="%s:$PATH"\n' "$LLVM_BIN" >> "$rc_file" + echo "Added LLVM bin to PATH in $rc_file" + fi + done + + # Export for the current shell session so make targets work immediately. + export PATH="$LLVM_BIN:$PATH" else # Ubuntu / Debian — clang 15 is the highest version available on Ubuntu 22.04. apt-get install -y clang-format-15 clang-tidy-15 cmake diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 05873a486..7aea7582b 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -12,25 +12,25 @@ """ import json +import subprocess import sys import sysconfig from pathlib import Path +from torch.utils.cpp_extension import include_paths as torch_include_paths -def main() -> None: - try: - import torch # noqa: F401 — imported to verify it is installed - from torch.utils.cpp_extension import include_paths as torch_include_paths - except ImportError as exc: - print( - f"Error: {exc}\n" - "Run `make build_cpp_extensions` first to ensure torch is available.", - file=sys.stderr, - ) - sys.exit(1) +def main() -> None: repo_root = Path(__file__).parent.parent.resolve() + # Always rebuild C++ extensions before generating compile_commands.json so + # the database reflects the current state of the code. + subprocess.run( + [sys.executable, "setup.py", "build_ext", "--inplace"], + cwd=repo_root, + check=True, + ) + # Collect all include directories needed to compile the extension. # torch_include_paths() returns the torch headers, which already bundle # pybind11 under torch/include/pybind11/ — no separate pybind11 import needed. @@ -62,7 +62,9 @@ def main() -> None: output = repo_root / "build" / "compile_commands.json" output.parent.mkdir(exist_ok=True) output.write_text(json.dumps(commands, indent=2)) - print(f"Wrote {len(commands)} entr{'y' if len(commands) == 1 else 'ies'} to {output}") + print( + f"Wrote {len(commands)} entr{'y' if len(commands) == 1 else 'ies'} to {output}" + ) if __name__ == "__main__": From 9d3c8df496755b36f81e1fde551fd0238c3938be Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 20:00:20 +0000 Subject: [PATCH 005/148] Rename setup.py to build_cpp_extensions.py; add build_cpp_extensions make target --- Makefile | 3 +++ setup.py => build_cpp_extensions.py | 9 --------- gigl/scripts/post_install.py | 4 ++-- scripts/generate_compile_commands.py | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) rename setup.py => build_cpp_extensions.py (71%) diff --git a/Makefile b/Makefile index f13be1c18..7e215c650 100644 --- a/Makefile +++ b/Makefile @@ -161,6 +161,9 @@ format: format_py format_scala format_md format_cpp type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs +build_cpp_extensions: + uv run --no-sync python build_cpp_extensions.py build_ext --inplace + lint_cpp: uv run python scripts/generate_compile_commands.py clang-tidy -p build/compile_commands.json $(CPP_SOURCES) diff --git a/setup.py b/build_cpp_extensions.py similarity index 71% rename from setup.py rename to build_cpp_extensions.py index a9678da1f..99ca11a6a 100644 --- a/setup.py +++ b/build_cpp_extensions.py @@ -11,20 +11,11 @@ def find_cpp_extensions() -> list[CppExtension]: extension. The module name is derived from the file path, so the extension is importable at the same location as its Python neighbours. - Example:: - - gigl/distributed/cpp_extensions/ppr_forward_push.cpp - → importable as ``gigl.distributed.cpp_extensions.ppr_forward_push`` - To add a new extension, drop a .cpp file anywhere under ``gigl/`` — no changes to this file required. """ extensions = [] for cpp_file in sorted(Path("gigl").rglob("*.cpp")): - # Convert path separators to dots and strip the .cpp suffix to get the - # fully-qualified Python module name, e.g.: - # gigl/distributed/cpp_extensions/ppr_forward_push.cpp - # → "gigl.distributed.cpp_extensions.ppr_forward_push" module_name = ".".join(cpp_file.with_suffix("").parts) extensions.append( CppExtension( diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index 918d62fb5..93d517f31 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -61,9 +61,9 @@ def main(): # Step 2: Build pybind11 C++ extensions in-place so they are importable # without requiring a separate `make build_cpp_extensions` call. - setup_py = repo_root / "setup.py" + setup_py = repo_root / "build_cpp_extensions.py" if setup_py.exists(): - cmd = f"cd {repo_root} && {sys.executable} setup.py build_ext --inplace" + cmd = f"cd {repo_root} && {sys.executable} build_cpp_extensions.py build_ext --inplace" try: print("Building C++ extensions...") result = run_command_and_stream_stdout(cmd) diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 7aea7582b..a3f77ef5f 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -26,7 +26,7 @@ def main() -> None: # Always rebuild C++ extensions before generating compile_commands.json so # the database reflects the current state of the code. subprocess.run( - [sys.executable, "setup.py", "build_ext", "--inplace"], + [sys.executable, "build_cpp_extensions.py", "build_ext", "--inplace"], cwd=repo_root, check=True, ) From ace71264cc046e4a9cef2ba43eb2c9b8276e79cd Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 20:02:34 +0000 Subject: [PATCH 006/148] Scope C++ extension discovery to gigl/cpp_extensions/ --- Makefile | 2 +- build_cpp_extensions.py | 12 ++++-------- scripts/generate_compile_commands.py | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 7e215c650..e0f05494c 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG?=${DOCKER_IMAGE_MAIN_CPU_NAME}:${DATE} DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${DATE} PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts -CPP_SOURCES:=$(shell find gigl -name "*.cpp") +CPP_SOURCES:=$(shell find gigl/cpp_extensions -name "*.cpp" 2>/dev/null) PY_TEST_FILES?="*_test.py" # You can override GIGL_TEST_DEFAULT_RESOURCE_CONFIG by setting it in your environment i.e. # adding `export GIGL_TEST_DEFAULT_RESOURCE_CONFIG=your_resource_config` to your shell config (~/.bashrc, ~/.zshrc, etc.) diff --git a/build_cpp_extensions.py b/build_cpp_extensions.py index 99ca11a6a..406f02a6e 100644 --- a/build_cpp_extensions.py +++ b/build_cpp_extensions.py @@ -5,17 +5,13 @@ def find_cpp_extensions() -> list[CppExtension]: - """Auto-discover pybind11 extension modules. + """Auto-discover pybind11 extension modules under ``gigl/cpp_extensions/``. - Any .cpp file anywhere under ``gigl/`` is compiled as a Python C++ - extension. The module name is derived from the file path, so the - extension is importable at the same location as its Python neighbours. - - To add a new extension, drop a .cpp file anywhere under ``gigl/`` — - no changes to this file required. + The module name is derived from the file path, so each extension is + importable at the Python path corresponding to its location. """ extensions = [] - for cpp_file in sorted(Path("gigl").rglob("*.cpp")): + for cpp_file in sorted(Path("gigl/cpp_extensions").rglob("*.cpp")): module_name = ".".join(cpp_file.with_suffix("").parts) extensions.append( CppExtension( diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index a3f77ef5f..630febfd7 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -40,7 +40,7 @@ def main() -> None: # Python C API headers (e.g. Python.h) required by pybind11. include_flags.append(f"-I{sysconfig.get_path('include')}") - cpp_sources = sorted((repo_root / "gigl").rglob("*.cpp")) + cpp_sources = sorted((repo_root / "gigl" / "cpp_extensions").rglob("*.cpp")) if not cpp_sources: print("Warning: no .cpp files found under gigl/", file=sys.stderr) From 48be4ccbbcddea57f80e33664ef3ea6fea7fce75 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 20:05:53 +0000 Subject: [PATCH 007/148] Remove unnecessary existence check for build_cpp_extensions.py in post_install --- gigl/scripts/post_install.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index 93d517f31..f7ee5c1cd 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -61,21 +61,17 @@ def main(): # Step 2: Build pybind11 C++ extensions in-place so they are importable # without requiring a separate `make build_cpp_extensions` call. - setup_py = repo_root / "build_cpp_extensions.py" - if setup_py.exists(): - cmd = f"cd {repo_root} && {sys.executable} build_cpp_extensions.py build_ext --inplace" - try: - print("Building C++ extensions...") - result = run_command_and_stream_stdout(cmd) - print("C++ extension build finished with return code:", result) - except subprocess.CalledProcessError as e: - print(f"Error building C++ extensions: {e}") - sys.exit(1) - except Exception as e: - print(f"Unexpected error building C++ extensions: {e}") - sys.exit(1) - else: - print(f"Warning: {setup_py} not found, skipping C++ extension build") + cmd = f"cd {repo_root} && {sys.executable} build_cpp_extensions.py build_ext --inplace" + try: + print("Building C++ extensions...") + result = run_command_and_stream_stdout(cmd) + print("C++ extension build finished with return code:", result) + except subprocess.CalledProcessError as e: + print(f"Error building C++ extensions: {e}") + sys.exit(1) + except Exception as e: + print(f"Unexpected error building C++ extensions: {e}") + sys.exit(1) return result From 1b153b7fdab0a3e7460664560f803c70ec31c6f0 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 20:29:30 +0000 Subject: [PATCH 008/148] Review fixes + adopt PyTorch csrc conventions for C++ layout --- .clang-tidy | 8 ------- Makefile | 6 ++--- build_cpp_extensions.py | 33 ++++++++++++++++++++++---- gigl/scripts/post_install.py | 16 ++++++------- requirements/install_cpp_deps.sh | 4 +++- scripts/generate_compile_commands.py | 5 ++-- tests/unit/cpp/CMakeLists.txt | 3 +-- tests/unit/cpp/infrastructure_test.cpp | 3 +-- 8 files changed, 47 insertions(+), 31 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 2c746e6b2..fe02e7100 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -27,11 +27,3 @@ WarningsAsErrors: "*" # Only apply header-file checks to GiGL-owned headers, not third-party # (torch, pybind11) headers pulled in by includes. HeaderFilterRegex: "gigl/.*" - -# Per-check configuration options. -CheckOptions: - # Enforce lower_case naming for local variables (matches existing style). - - key: readability-identifier-naming.LocalVariableCase - value: lower_case - - key: readability-identifier-naming.ParameterCase - value: lower_case diff --git a/Makefile b/Makefile index e0f05494c..86fea095e 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG?=${DOCKER_IMAGE_MAIN_CPU_NAME}:${DATE} DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${DATE} PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts -CPP_SOURCES:=$(shell find gigl/cpp_extensions -name "*.cpp" 2>/dev/null) +CPP_SOURCES:=$(shell find gigl/csrc -name "*.cpp" 2>/dev/null) PY_TEST_FILES?="*_test.py" # You can override GIGL_TEST_DEFAULT_RESOURCE_CONFIG by setting it in your environment i.e. # adding `export GIGL_TEST_DEFAULT_RESOURCE_CONFIG=your_resource_config` to your shell config (~/.bashrc, ~/.zshrc, etc.) @@ -117,7 +117,7 @@ check_format_md: uv run mdformat --check ${MD_FILES} check_format_cpp: - clang-format --dry-run --Werror --style=file $(CPP_SOURCES) + $(if $(CPP_SOURCES), clang-format --dry-run --Werror --style=file $(CPP_SOURCES)) check_format: check_format_py check_format_scala check_format_md check_format_cpp @@ -154,7 +154,7 @@ format_md: uv run mdformat ${MD_FILES} format_cpp: - clang-format -i --style=file $(CPP_SOURCES) + $(if $(CPP_SOURCES), clang-format -i --style=file $(CPP_SOURCES)) format: format_py format_scala format_md format_cpp diff --git a/build_cpp_extensions.py b/build_cpp_extensions.py index 406f02a6e..53c823333 100644 --- a/build_cpp_extensions.py +++ b/build_cpp_extensions.py @@ -1,18 +1,41 @@ +"""Build script for GiGL pybind11 C++ extensions. + +Invoked by ``make build_cpp_extensions`` and automatically during ``make install_dev_deps`` +via ``post_install.py``. Not a general-purpose setup.py — only builds C++ extensions. + +Usage:: + + python build_cpp_extensions.py build_ext --inplace +""" + from pathlib import Path from setuptools import setup from torch.utils.cpp_extension import BuildExtension, CppExtension +_CSRC_DIR = Path("gigl/csrc") + def find_cpp_extensions() -> list[CppExtension]: - """Auto-discover pybind11 extension modules under ``gigl/cpp_extensions/``. + """Auto-discover pybind11 extension modules under ``gigl/csrc/``. + + Following PyTorch's csrc convention, only files named ``python_*.cpp`` are + compiled as Python extension modules. Pure C++ files (without the + ``python_`` prefix) are used only in C++ unit tests. + + The module name is derived from the file path with the ``python_`` prefix + stripped, so ``gigl/csrc/distributed/python_ppr_forward_push.cpp`` is + importable as ``gigl.csrc.distributed.ppr_forward_push``. - The module name is derived from the file path, so each extension is - importable at the Python path corresponding to its location. + Returns an empty list if ``gigl/csrc/`` does not yet exist. """ + if not _CSRC_DIR.exists(): + return [] extensions = [] - for cpp_file in sorted(Path("gigl/cpp_extensions").rglob("*.cpp")): - module_name = ".".join(cpp_file.with_suffix("").parts) + for cpp_file in sorted(_CSRC_DIR.rglob("python_*.cpp")): + parts = list(cpp_file.with_suffix("").parts) + parts[-1] = parts[-1].removeprefix("python_") + module_name = ".".join(parts) extensions.append( CppExtension( name=module_name, diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index f7ee5c1cd..677e45a6c 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -52,20 +52,22 @@ def main(): print(f"Executing bash {install_glt_script}...") result = run_command_and_stream_stdout(f"bash {install_glt_script}") print("GLT install finished with return code:", result) - except subprocess.CalledProcessError as e: - print(f"Error running install_glt.sh: {e}") - sys.exit(1) except Exception as e: print(f"Unexpected error: {e}") sys.exit(1) # Step 2: Build pybind11 C++ extensions in-place so they are importable # without requiring a separate `make build_cpp_extensions` call. - cmd = f"cd {repo_root} && {sys.executable} build_cpp_extensions.py build_ext --inplace" + # subprocess.run streams stdout/stderr to the terminal and raises + # CalledProcessError on a non-zero exit code. try: print("Building C++ extensions...") - result = run_command_and_stream_stdout(cmd) - print("C++ extension build finished with return code:", result) + subprocess.run( + [sys.executable, "build_cpp_extensions.py", "build_ext", "--inplace"], + cwd=repo_root, + check=True, + ) + print("C++ extension build finished.") except subprocess.CalledProcessError as e: print(f"Error building C++ extensions: {e}") sys.exit(1) @@ -73,8 +75,6 @@ def main(): print(f"Unexpected error building C++ extensions: {e}") sys.exit(1) - return result - if __name__ == "__main__": main() diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 7675a0396..6b9f19113 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -30,7 +30,9 @@ if is_running_on_mac; then fi done - # Export for the current shell session so make targets work immediately. + # NOTE: this export only affects subprocesses of this script, not the calling + # shell or make process. Open a new terminal (or run `source ~/.zshrc`) after + # install_dev_deps to pick up the PATH change. export PATH="$LLVM_BIN:$PATH" else # Ubuntu / Debian — clang 15 is the highest version available on Ubuntu 22.04. diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 630febfd7..767a4860b 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -40,9 +40,10 @@ def main() -> None: # Python C API headers (e.g. Python.h) required by pybind11. include_flags.append(f"-I{sysconfig.get_path('include')}") - cpp_sources = sorted((repo_root / "gigl" / "cpp_extensions").rglob("*.cpp")) + cpp_dir = repo_root / "gigl" / "csrc" + cpp_sources = sorted(cpp_dir.rglob("*.cpp")) if cpp_dir.exists() else [] if not cpp_sources: - print("Warning: no .cpp files found under gigl/", file=sys.stderr) + print("Warning: no .cpp files found under gigl/csrc/", file=sys.stderr) # Each entry in compile_commands.json describes how one source file is compiled. # clang-tidy reads this to reproduce the exact compilation environment. diff --git a/tests/unit/cpp/CMakeLists.txt b/tests/unit/cpp/CMakeLists.txt index fd55255b2..514625587 100644 --- a/tests/unit/cpp/CMakeLists.txt +++ b/tests/unit/cpp/CMakeLists.txt @@ -12,8 +12,7 @@ include(FetchContent) FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz - # TODO: pin URL_HASH once infrastructure is validated, e.g.: - # URL_HASH SHA256= + URL_HASH SHA256=8372520bab45e12a97cd2f49dad36d07e55ddb89c0e39fad4a1a64cab0bdf35d ) # Prevent GoogleTest from overriding the compiler's runtime on Windows # (no-op on Linux/Mac, but required for portable CMake config). diff --git a/tests/unit/cpp/infrastructure_test.cpp b/tests/unit/cpp/infrastructure_test.cpp index d8d252f8e..af85a6660 100644 --- a/tests/unit/cpp/infrastructure_test.cpp +++ b/tests/unit/cpp/infrastructure_test.cpp @@ -1,8 +1,7 @@ // Placeholder C++ unit test. // // This file exists to verify that the GoogleTest infrastructure compiles and -// runs end-to-end. Replace or supplement it with tests for actual GiGL C++ -// code (e.g. PPRForwardPushState) as those components are added. +// runs end-to-end. #include From 03ed8c458c3478f981e9c8b85805af79c8c607ff Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 21:52:34 +0000 Subject: [PATCH 009/148] Add multi-source C++ ext support, gigl/csrc package init, and .so gitignore --- .gitignore | 3 +++ build_cpp_extensions.py | 10 +++++++++- gigl/csrc/__init__.py | 0 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 gigl/csrc/__init__.py diff --git a/.gitignore b/.gitignore index e06a57bc8..da3c883c5 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ fossa*.zip # https://github.com/google-github-actions/auth/issues/497 gha-creds-*.json + +# Compiled C++ extension modules +gigl/csrc/**/*.so diff --git a/build_cpp_extensions.py b/build_cpp_extensions.py index 53c823333..a0095464a 100644 --- a/build_cpp_extensions.py +++ b/build_cpp_extensions.py @@ -27,6 +27,10 @@ def find_cpp_extensions() -> list[CppExtension]: stripped, so ``gigl/csrc/distributed/python_ppr_forward_push.cpp`` is importable as ``gigl.csrc.distributed.ppr_forward_push``. + If a matching implementation file exists alongside the binding file (e.g. + ``ppr_forward_push.cpp`` next to ``python_ppr_forward_push.cpp``), it is + compiled into the same extension module. + Returns an empty list if ``gigl/csrc/`` does not yet exist. """ if not _CSRC_DIR.exists(): @@ -36,10 +40,14 @@ def find_cpp_extensions() -> list[CppExtension]: parts = list(cpp_file.with_suffix("").parts) parts[-1] = parts[-1].removeprefix("python_") module_name = ".".join(parts) + impl_file = cpp_file.parent / (parts[-1] + ".cpp") + sources = [str(cpp_file)] + if impl_file.exists(): + sources.append(str(impl_file)) extensions.append( CppExtension( name=module_name, - sources=[str(cpp_file)], + sources=sources, extra_compile_args=["-O3", "-std=c++17", "-Wall", "-Wextra"], ) ) diff --git a/gigl/csrc/__init__.py b/gigl/csrc/__init__.py new file mode 100644 index 000000000..e69de29bb From 87dc95b08b289bcc814daa8aebe5eebe8012a5bd Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 24 Mar 2026 20:24:14 +0000 Subject: [PATCH 010/148] Initial commit --- gigl/distributed/cpp_extensions/__init__.py | 9 + .../cpp_extensions/ppr_forward_push.cpp | 294 +++++++++++++ .../cpp_extensions/ppr_forward_push.pyi | 21 + gigl/distributed/dist_ppr_sampler.py | 388 +++++++----------- 4 files changed, 463 insertions(+), 249 deletions(-) create mode 100644 gigl/distributed/cpp_extensions/__init__.py create mode 100644 gigl/distributed/cpp_extensions/ppr_forward_push.cpp create mode 100644 gigl/distributed/cpp_extensions/ppr_forward_push.pyi diff --git a/gigl/distributed/cpp_extensions/__init__.py b/gigl/distributed/cpp_extensions/__init__.py new file mode 100644 index 000000000..d375f59b1 --- /dev/null +++ b/gigl/distributed/cpp_extensions/__init__.py @@ -0,0 +1,9 @@ +try: + from gigl.distributed.cpp_extensions.ppr_forward_push import PPRForwardPushState +except ImportError as e: + raise ImportError( + "PPR C++ extension not compiled. " + "Run `uv pip install -e .` from the GiGL root to build it." + ) from e + +__all__ = ["PPRForwardPushState"] diff --git a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp new file mode 100644 index 000000000..6f6d10545 --- /dev/null +++ b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp @@ -0,0 +1,294 @@ +#include +#include + +#include +#include +#include +#include +#include + +namespace py = pybind11; + +// Pack (node_id, etype_id) into a single uint64_t lookup key. +// Requires both values fit in 32 bits — enforced by the Python caller. +static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { + return (static_cast(static_cast(node_id)) << 32) | + static_cast(etype_id); +} + +// C++ kernel for the PPR Forward Push algorithm (Andersen et al., 2006). +// +// Owned state: ppr_scores, residuals, queue, queued_nodes, neighbor_cache. +// Python retains ownership of: the distributed neighbor fetch (_batch_fetch_neighbors). +// +// Typical call sequence per batch: +// 1. PPRForwardPushState(seed_nodes, ...) — init per-seed residuals / queue +// while True: +// 2. drain_queue() — drain queue → nodes needing lookup +// 3. — distributed RPC fetch (stays in Python) +// 4. push_residuals(fetched_by_etype_id) — push residuals, update queue +// 5. extract_top_k(max_ppr_nodes) — top-k selection per seed per node type +class PPRForwardPushState { +public: + PPRForwardPushState( + torch::Tensor seed_nodes, + int32_t seed_node_type_id, + float alpha, + float requeue_threshold_factor, + std::vector> node_type_to_edge_type_ids, + std::vector edge_type_to_dst_ntype_id, + std::vector degree_tensors + ) + : alpha_(alpha), + one_minus_alpha_(1.0f - alpha), + requeue_threshold_factor_(requeue_threshold_factor), + node_type_to_edge_type_ids_(std::move(node_type_to_edge_type_ids)), + edge_type_to_dst_ntype_id_(std::move(edge_type_to_dst_ntype_id)), + degree_tensors_(std::move(degree_tensors)) { + + TORCH_CHECK(seed_nodes.dim() == 1, "seed_nodes must be 1D"); + batch_size_ = static_cast(seed_nodes.size(0)); + num_node_types_ = static_cast(node_type_to_edge_type_ids_.size()); + + ppr_scores_.assign(batch_size_, std::vector>(num_node_types_)); + residuals_.assign(batch_size_, std::vector>(num_node_types_)); + queue_.assign(batch_size_, std::vector>(num_node_types_)); + queued_nodes_.assign(batch_size_, std::vector>(num_node_types_)); + + auto acc = seed_nodes.accessor(); + num_nodes_in_queue_ = batch_size_; + for (int32_t i = 0; i < batch_size_; ++i) { + int32_t seed = static_cast(acc[i]); + residuals_[i][seed_node_type_id][seed] = alpha_; + queue_[i][seed_node_type_id].insert(seed); + } + } + + // Drain all queued nodes and return {etype_id: tensor[node_ids]} for batch + // neighbor lookup. Also snapshots the drained nodes into queued_nodes_ for + // use by push_residuals(). + // + // Returns None when the queue is truly empty (convergence signal). + // Returns a dict (possibly empty) when nodes were drained but all had cached + // neighbors or no outgoing edges — push_residuals must still be called to + // flush their residuals into ppr_scores_. + py::object drain_queue() { + if (num_nodes_in_queue_ == 0) { + return py::none(); + } + + for (int32_t s = 0; s < batch_size_; ++s) + for (auto& qs : queued_nodes_[s]) qs.clear(); + + std::unordered_map> nodes_to_lookup; + + for (int32_t s = 0; s < batch_size_; ++s) { + for (int32_t nt = 0; nt < num_node_types_; ++nt) { + if (queue_[s][nt].empty()) continue; + + // Snapshot queue into queued_nodes, then reset queue. + queued_nodes_[s][nt] = std::move(queue_[s][nt]); + queue_[s][nt].clear(); + num_nodes_in_queue_ -= static_cast(queued_nodes_[s][nt].size()); + + for (int32_t node_id : queued_nodes_[s][nt]) { + for (int32_t eid : node_type_to_edge_type_ids_[nt]) { + // Only add to lookup if not already in the persistent cache. + if (neighbor_cache_.find(pack_key(node_id, eid)) == neighbor_cache_.end()) { + nodes_to_lookup[eid].insert(node_id); + } + } + } + } + } + + py::dict result; + for (auto& [eid, node_set] : nodes_to_lookup) { + std::vector ids(node_set.begin(), node_set.end()); + result[py::int_(eid)] = torch::tensor(ids, torch::kLong); + } + return result; + } + + // Push residuals to neighbors given the fetched neighbor data. + // fetched_by_etype_id: {etype_id: (node_ids_tensor, flat_nbrs_tensor, counts_tensor)} + // - node_ids_tensor: [N] int64 — source node IDs fetched for this edge type + // - flat_nbrs_tensor: [sum(counts)] int64 — flat concatenation of all neighbor lists + // - counts_tensor: [N] int64 — number of neighbors for each source node + void push_residuals(py::dict fetched_by_etype_id) { + // Build local fetched map: pack_key(node_id, etype_id) -> neighbor list. + std::unordered_map> fetched; + for (auto item : fetched_by_etype_id) { + int32_t eid = item.first.cast(); + auto tup = item.second.cast(); + auto node_ids_t = tup[0].cast(); + auto flat_nbrs_t = tup[1].cast(); + auto counts_t = tup[2].cast(); + + auto node_acc = node_ids_t.accessor(); + auto nbr_acc = flat_nbrs_t.accessor(); + auto cnt_acc = counts_t.accessor(); + + int64_t offset = 0; + for (int64_t i = 0; i < node_ids_t.size(0); ++i) { + int32_t nid = static_cast(node_acc[i]); + int64_t count = cnt_acc[i]; + std::vector nbrs(count); + for (int64_t j = 0; j < count; ++j) + nbrs[j] = static_cast(nbr_acc[offset + j]); + fetched[pack_key(nid, eid)] = std::move(nbrs); + offset += count; + } + } + + for (int32_t s = 0; s < batch_size_; ++s) { + for (int32_t nt = 0; nt < num_node_types_; ++nt) { + if (queued_nodes_[s][nt].empty()) continue; + + for (int32_t src : queued_nodes_[s][nt]) { + auto& src_res = residuals_[s][nt]; + auto it = src_res.find(src); + float res = (it != src_res.end()) ? it->second : 0.0f; + + ppr_scores_[s][nt][src] += res; + src_res[src] = 0.0f; + + int32_t total_deg = get_total_degree(src, nt); + if (total_deg == 0) continue; + + float res_per_nbr = one_minus_alpha_ * res / static_cast(total_deg); + + for (int32_t eid : node_type_to_edge_type_ids_[nt]) { + // fetched and neighbor_cache are mutually exclusive per iteration: + // drain_queue only adds a node to nodes_to_lookup when absent from + // neighbor_cache, so a given key appears in at most one of the two. + const std::vector* nbr_list = nullptr; + auto fi = fetched.find(pack_key(src, eid)); + if (fi != fetched.end()) { + nbr_list = &fi->second; + } else { + auto ci = neighbor_cache_.find(pack_key(src, eid)); + if (ci != neighbor_cache_.end()) nbr_list = &ci->second; + } + if (!nbr_list || nbr_list->empty()) continue; + + int32_t dst_nt = edge_type_to_dst_ntype_id_[eid]; + + for (int32_t nbr : *nbr_list) { + residuals_[s][dst_nt][nbr] += res_per_nbr; + + float threshold = requeue_threshold_factor_ * + static_cast(get_total_degree(nbr, dst_nt)); + + if (queue_[s][dst_nt].find(nbr) == queue_[s][dst_nt].end() && + residuals_[s][dst_nt][nbr] >= threshold) { + queue_[s][dst_nt].insert(nbr); + ++num_nodes_in_queue_; + + // Promote this node's neighbor lists to the persistent cache: + // it will be processed next iteration, so caching now avoids + // a re-fetch. Nodes that are never requeued (typically + // high-degree) are never promoted, keeping their large neighbor + // lists out of the cache. + for (int32_t peid : node_type_to_edge_type_ids_[dst_nt]) { + uint64_t pk = pack_key(nbr, peid); + if (neighbor_cache_.find(pk) == neighbor_cache_.end()) { + auto pfi = fetched.find(pk); + if (pfi != fetched.end()) + neighbor_cache_[pk] = pfi->second; + } + } + } + } + } + } + } + } + } + + // Extract top-k PPR nodes per seed per node type. + // Returns {ntype_id: (flat_ids_tensor, flat_weights_tensor, valid_counts_tensor)}. + // Only node types that received any PPR score are included in the output. + py::dict extract_top_k(int32_t max_ppr_nodes) { + std::unordered_set active; + for (int32_t s = 0; s < batch_size_; ++s) + for (int32_t nt = 0; nt < num_node_types_; ++nt) + if (!ppr_scores_[s][nt].empty()) active.insert(nt); + + py::dict result; + for (int32_t nt : active) { + std::vector flat_ids; + std::vector flat_weights; + std::vector valid_counts; + + for (int32_t s = 0; s < batch_size_; ++s) { + const auto& scores = ppr_scores_[s][nt]; + int32_t k = std::min(max_ppr_nodes, static_cast(scores.size())); + if (k > 0) { + std::vector> items(scores.begin(), scores.end()); + std::partial_sort(items.begin(), items.begin() + k, items.end(), + [](const auto& a, const auto& b) { return a.second > b.second; }); + for (int32_t i = 0; i < k; ++i) { + flat_ids.push_back(static_cast(items[i].first)); + flat_weights.push_back(items[i].second); + } + } + valid_counts.push_back(static_cast(k)); + } + + result[py::int_(nt)] = py::make_tuple( + torch::tensor(flat_ids, torch::kLong), + torch::tensor(flat_weights, torch::kFloat), + torch::tensor(valid_counts, torch::kLong) + ); + } + return result; + } + +private: + int32_t get_total_degree(int32_t node_id, int32_t ntype_id) const { + if (ntype_id >= static_cast(degree_tensors_.size())) return 0; + const auto& t = degree_tensors_[ntype_id]; + if (t.numel() == 0) return 0; // destination-only type: no outgoing edges + TORCH_CHECK( + node_id < static_cast(t.size(0)), + "Node ID ", node_id, " out of range for degree tensor of ntype_id ", ntype_id, + " (size=", t.size(0), "). This indicates corrupted graph data or a sampler bug." + ); + return t.data_ptr()[node_id]; + } + + float alpha_, one_minus_alpha_, requeue_threshold_factor_; + int32_t batch_size_, num_node_types_, num_nodes_in_queue_{0}; + + std::vector> node_type_to_edge_type_ids_; + std::vector edge_type_to_dst_ntype_id_; + std::vector degree_tensors_; + + // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]). + std::vector>> ppr_scores_; + std::vector>> residuals_; + std::vector>> queue_; + // Snapshot of queue contents from the last drain_queue() call, used by push_residuals(). + std::vector>> queued_nodes_; + + // Persistent neighbor cache: pack_key(node_id, etype_id) -> neighbor list. + // Only nodes that have been requeued (and thus will be processed again) are + // promoted here from the per-iteration fetched map. + std::unordered_map> neighbor_cache_; +}; + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + py::class_(m, "PPRForwardPushState") + .def(py::init< + torch::Tensor, + int32_t, + float, float, + std::vector>, + std::vector, + std::vector + >()) + .def("drain_queue", &PPRForwardPushState::drain_queue) + .def("push_residuals", &PPRForwardPushState::push_residuals) + .def("extract_top_k", &PPRForwardPushState::extract_top_k); +} diff --git a/gigl/distributed/cpp_extensions/ppr_forward_push.pyi b/gigl/distributed/cpp_extensions/ppr_forward_push.pyi new file mode 100644 index 000000000..265468c3c --- /dev/null +++ b/gigl/distributed/cpp_extensions/ppr_forward_push.pyi @@ -0,0 +1,21 @@ +import torch + +class PPRForwardPushState: + def __init__( + self, + seed_nodes: torch.Tensor, + seed_node_type_id: int, + alpha: float, + requeue_threshold_factor: float, + node_type_to_edge_type_ids: list[list[int]], + edge_type_to_dst_ntype_id: list[int], + degree_tensors: list[torch.Tensor], + ) -> None: ... + def drain_queue(self) -> dict[int, torch.Tensor] | None: ... + def push_residuals( + self, + fetched_by_etype_id: dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]], + ) -> None: ... + def extract_top_k( + self, max_ppr_nodes: int + ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: ... diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 17673a72d..cf4c732c0 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -1,14 +1,6 @@ -# TODO (mkolodner-sc): The forward push loop in _compute_ppr_scores is the -# main throughput bottleneck — both the queue drain (preparing batched node -# lookups by edge type) and the residual push/requeue pass are pure Python -# dict/set operations in tight nested loops. Moving these to a C++ extension -# (e.g. pybind11) would eliminate per-operation Python overhead and enable -# cache-friendly memory access patterns. - # TODO (mkolodner-sc): Investigate whether concurrency for _sample_one_hop and _compute_ppr_scores will # yield performance benefits. -import heapq from collections import defaultdict from typing import Optional, Union @@ -22,6 +14,7 @@ from graphlearn_torch.typing import EdgeType, NodeType from graphlearn_torch.utils import merge_dict +from gigl.distributed.cpp_extensions import PPRForwardPushState from gigl.distributed.dist_neighbor_sampler import DistNeighborSampler from gigl.types.graph import is_label_edge_type @@ -48,6 +41,49 @@ ) +def _group_fetched_by_etype_id( + fetched: dict[tuple[int, EdgeType], list[int]], + etype_to_etype_id: dict[EdgeType, int], +) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: + """Group batch-fetched neighbors by integer edge type ID for the C++ push kernel. + + Performs one linear pass over the fetched dict, building flat tensors per + edge type. This avoids per-neighbor Python overhead in push_residuals by + batching all lookups for the same edge type together. + + Args: + fetched: Output of _batch_fetch_neighbors: ``(node_id, etype)`` → + neighbor list. + etype_to_etype_id: Mapping from EdgeType to its integer ID. + + Returns: + Dict mapping etype_id to ``(node_ids, flat_neighbors, counts)`` as + flat int64 tensors. ``flat_neighbors`` is the concatenation of all + neighbor lists for that edge type; ``counts[i]`` gives the neighbor + count for ``node_ids[i]``. + """ + node_ids_by_etype: dict[int, list[int]] = {} + flat_nbrs_by_etype: dict[int, list[int]] = {} + counts_by_etype: dict[int, list[int]] = {} + for (node_id, etype), neighbors in fetched.items(): + eid = etype_to_etype_id[etype] + if eid not in node_ids_by_etype: + node_ids_by_etype[eid] = [] + flat_nbrs_by_etype[eid] = [] + counts_by_etype[eid] = [] + node_ids_by_etype[eid].append(node_id) + flat_nbrs_by_etype[eid].extend(neighbors) + counts_by_etype[eid].append(len(neighbors)) + return { + eid: ( + torch.tensor(node_ids_by_etype[eid], dtype=torch.long), + torch.tensor(flat_nbrs_by_etype[eid], dtype=torch.long), + torch.tensor(counts_by_etype[eid], dtype=torch.long), + ) + for eid in node_ids_by_etype + } + + # TODO (mkolodner-sc): Consider introducing a BaseGiGLSampler that owns # shared utilities like _prepare_sample_loop_inputs, with KHopSampler and # PPRSampler as siblings. Currently DistPPRNeighborSampler inherits from @@ -157,6 +193,56 @@ def __init__( NodeType, torch.Tensor ] = self._build_total_degree_tensors(degree_tensors, total_degree_dtype) + # Build integer ID mappings for the C++ forward-push kernel. String + # NodeType / EdgeType keys are only used at the Python boundary + # (translating to/from _batch_fetch_neighbors); all hot-loop state inside + # PPRForwardPushState is indexed by int32 IDs. + # + # We include both source types (have outgoing edges) and destination-only + # types (no outgoing edges, but may accumulate PPR score during the walk) + # so the kernel can index residual/ppr_score tables for any node it sees. + _all_node_types: list[NodeType] = sorted( + {nt for nt in self._node_type_to_edge_types} + | { + self._get_destination_type(et) + for etypes in self._node_type_to_edge_types.values() + for et in etypes + } + ) + # dict.fromkeys preserves insertion order while deduplicating. + _all_edge_types: list[EdgeType] = list( + dict.fromkeys( + et for etypes in self._node_type_to_edge_types.values() for et in etypes + ) + ) + + self._node_type_to_id: dict[NodeType, int] = { + nt: i for i, nt in enumerate(_all_node_types) + } + self._ntype_id_to_ntype: list[NodeType] = _all_node_types + self._etype_to_etype_id: dict[EdgeType, int] = { + et: i for i, et in enumerate(_all_edge_types) + } + self._etype_id_to_etype: list[EdgeType] = _all_edge_types + + self._node_type_id_to_edge_type_ids: list[list[int]] = [ + [ + self._etype_to_etype_id[et] + for et in self._node_type_to_edge_types.get(nt, []) + ] + for nt in _all_node_types + ] + self._edge_type_id_to_dst_ntype_id: list[int] = [ + self._node_type_to_id[self._get_destination_type(et)] + for et in _all_edge_types + ] + # Degree tensors indexed by ntype_id. Destination-only types get an empty + # tensor; the C++ kernel returns 0 for those, matching _get_total_degree. + self._degree_tensors_for_cpp: list[torch.Tensor] = [ + self._node_type_to_total_degree.get(nt, torch.zeros(0, dtype=torch.int32)) + for nt in _all_node_types + ] + def _build_total_degree_tensors( self, degree_tensors: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], @@ -209,35 +295,6 @@ def _build_total_degree_tensors( return result - def _get_total_degree(self, node_id: int, node_type: NodeType) -> int: - """Look up the precomputed total degree of a node. - - Args: - node_id: The ID of the node to look up. - node_type: The node type. - - Returns: - The total degree (sum across all edge types) for the node. - - Raises: - ValueError: If the node ID is out of range, indicating corrupted - graph data or a sampler bug. - """ - # Destination-only node types (no outgoing edges) are absent from - # _node_type_to_total_degree because total degree is only computed for - # traversable source types. Returning 0 here is correct: such nodes - # act as terminals — they accumulate PPR score but never push residual - # further. - if node_type not in self._node_type_to_total_degree: - return 0 - degree_tensor = self._node_type_to_total_degree[node_type] - if node_id >= len(degree_tensor): - raise ValueError( - f"Node ID {node_id} exceeds total degree tensor length " - f"({len(degree_tensor)}) for node type {node_type}." - ) - return int(degree_tensor[node_id].item()) - def _get_destination_type(self, edge_type: EdgeType) -> NodeType: """Get the node type at the destination end of an edge type.""" return edge_type[0] if self.edge_dir == "in" else edge_type[-1] @@ -369,226 +426,59 @@ async def _compute_ppr_scores( if seed_node_type is None: seed_node_type = _PPR_HOMOGENEOUS_NODE_TYPE device = seed_nodes.device - batch_size = seed_nodes.size(0) - - # Per-seed PPR state, nested by node type for efficient type-grouped access. - - # ppr_scores[i][node_type][node_id] = accumulated PPR score for node_id - # of type node_type, relative to seed i. Updated each iteration by - # absorbing the node's residual. - ppr_scores: list[dict[NodeType, dict[int, float]]] = [ - defaultdict(lambda: defaultdict(float)) for _ in range(batch_size) - ] - # residuals[i][node_type][node_id] = unconverged probability mass at node_id - # of type node_type for seed i. Each iteration, a node's residual is - # absorbed into its PPR score and then distributed to its neighbors. - residuals: list[dict[NodeType, dict[int, float]]] = [ - defaultdict(lambda: defaultdict(float)) for _ in range(batch_size) - ] - - # queue[i][node_type] = set of node IDs whose residual exceeds the - # convergence threshold (alpha * eps * total_degree). The algorithm - # terminates when all queues are empty. A set is used because multiple - # neighbors can push residual to the same node in one iteration — - # deduplication avoids redundant processing, and the O(1) membership - # check matters since it runs in the innermost loop. - queue: list[dict[NodeType, set[int]]] = [ - defaultdict(set) for _ in range(batch_size) - ] - - seed_list = seed_nodes.tolist() - - for i, seed in enumerate(seed_list): - residuals[i][seed_node_type][seed] = self._alpha - queue[i][seed_node_type].add(seed) - - # Cache keyed by (node_id, edge_type) since same node can have different neighbors per edge type - neighbor_cache: dict[tuple[int, EdgeType], list[int]] = {} - - num_nodes_in_queue = batch_size - one_minus_alpha = 1 - self._alpha - - while num_nodes_in_queue > 0: - # Drain all nodes from all queues and group by edge type for batched lookups - queued_nodes: list[dict[NodeType, set[int]]] = [ - defaultdict(set) for _ in range(batch_size) - ] - nodes_to_lookup: dict[EdgeType, set[int]] = defaultdict(set) - - for seed_idx in range(batch_size): - if queue[seed_idx]: - queued_nodes[seed_idx] = queue[seed_idx] - queue[seed_idx] = defaultdict(set) - for node_type, node_ids in queued_nodes[seed_idx].items(): - num_nodes_in_queue -= len(node_ids) - # We fetch neighbors for ALL edge types originating - # from this node type, not just the edge type that - # caused the node to be queued. This is required for - # correctness: forward push distributes residual to - # all neighbors proportionally by total degree, so - # every edge type must be considered. - # Destination-only types have no entry in _node_type_to_edge_types; - # .get() returns [] so we skip neighbor lookup for them. - edge_types_for_node = self._node_type_to_edge_types.get( - node_type, [] - ) - for node_id in node_ids: - for etype in edge_types_for_node: - cache_key = (node_id, etype) - if cache_key not in neighbor_cache: - # TODO (mkolodner-sc): Investigate switching from set to list - # here. _sample_one_hop handles duplicates correctly (second - # write to result[(node_id, etype)] is a no-op overwrite), so - # dedup is not required for correctness. A list would avoid - # per-add hash cost and the set->list->tensor conversion in - # _batch_fetch_neighbors, though at the cost of redundant - # network calls for any duplicate nodes across seeds. - nodes_to_lookup[etype].add(node_id) - - fetched_neighbors = await self._batch_fetch_neighbors( - nodes_to_lookup=nodes_to_lookup, - device=device, - ) - # fetched_neighbors is intentionally NOT merged into neighbor_cache - # upfront. We only promote entries when a node is requeued — see - # the should_requeue block below. - - # Push residual to neighbors and re-queue in a single pass. This - # is safe because each seed's state is independent, and residuals - # are always positive so the merged loop can never miss a re-queue. - for seed_idx in range(batch_size): - for source_type, source_nodes in queued_nodes[seed_idx].items(): - for source_node in source_nodes: - source_residual = residuals[seed_idx][source_type].get( - source_node, 0.0 - ) - - ppr_scores[seed_idx][source_type][ - source_node - ] += source_residual - residuals[seed_idx][source_type][source_node] = 0.0 - - # Same destination-only guard as in the queue drain loop above. - edge_types_for_node = self._node_type_to_edge_types.get( - source_type, [] - ) - - total_degree = self._get_total_degree(source_node, source_type) - - if total_degree == 0: - continue + ppr_state = PPRForwardPushState( + seed_nodes, + self._node_type_to_id[seed_node_type], + self._alpha, + self._requeue_threshold_factor, + self._node_type_id_to_edge_type_ids, + self._edge_type_id_to_dst_ntype_id, + self._degree_tensors_for_cpp, + ) - residual_per_neighbor = ( - one_minus_alpha * source_residual / total_degree - ) + while True: + # drain_queue returns None when the queue is truly empty (convergence), + # or a dict (possibly empty) when nodes were drained. An empty dict + # means all drained nodes either had cached neighbors or no outgoing + # edges — we still call push_residuals to flush their residuals into + # ppr_scores_. + drain_result: dict[int, torch.Tensor] | None = ppr_state.drain_queue() + if drain_result is None: + break + + nodes_by_etype_id: dict[int, torch.Tensor] = drain_result + if nodes_by_etype_id: + # Translate integer etype IDs back to EdgeType for the distributed + # fetch layer. O(num_active_etypes) — negligible vs. RPC round-trip. + nodes_to_lookup: dict[EdgeType, set[int]] = { + self._etype_id_to_etype[eid]: set(t.tolist()) + for eid, t in nodes_by_etype_id.items() + } + fetched_neighbors = await self._batch_fetch_neighbors( + nodes_to_lookup, device + ) + fetched_by_etype_id = _group_fetched_by_etype_id( + fetched_neighbors, self._etype_to_etype_id + ) + else: + fetched_by_etype_id = {} - for etype in edge_types_for_node: - cache_key = (source_node, etype) - # fetched_neighbors and neighbor_cache are mutually - # exclusive per iteration: the queue drain only adds - # a node to nodes_to_lookup if it is absent from - # neighbor_cache, so a key appears in at most one. - neighbor_list = fetched_neighbors.get( - cache_key, neighbor_cache.get(cache_key, []) - ) - if not neighbor_list: - continue - - neighbor_type = self._get_destination_type(etype) - - for neighbor_node in neighbor_list: - residuals[seed_idx][neighbor_type][ - neighbor_node - ] += residual_per_neighbor - - requeue_threshold = ( - self._requeue_threshold_factor - * self._get_total_degree( - neighbor_node, neighbor_type - ) - ) - should_requeue = ( - neighbor_node not in queue[seed_idx][neighbor_type] - and residuals[seed_idx][neighbor_type][ - neighbor_node - ] - >= requeue_threshold - ) - if should_requeue: - queue[seed_idx][neighbor_type].add(neighbor_node) - num_nodes_in_queue += 1 - # Promote this node's neighbor lists to the - # persistent cache: it will be processed next - # iteration, so caching now avoids a re-fetch. - # Nodes that are never requeued (typically - # high-degree) are never promoted, keeping - # their large neighbor lists out of the cache. - for ( - promote_etype - ) in self._node_type_to_edge_types.get( - neighbor_type, [] - ): - promote_key = (neighbor_node, promote_etype) - if ( - promote_key in fetched_neighbors - and promote_key not in neighbor_cache - ): - neighbor_cache[ - promote_key - ] = fetched_neighbors[promote_key] - - # Extract top-k nodes by PPR score, grouped by node type. - # Results are three flat tensors per node type (no padding): - # - flat_ids: [id_seed0_0, id_seed0_1, ..., id_seed1_0, ...] - # - flat_weights: [wt_seed0_0, wt_seed0_1, ..., wt_seed1_0, ...] - # - valid_counts: [count_seed0, count_seed1, ...] - # - # valid_counts[i] records how many top-k neighbors seed i contributed. - # The inducer uses valid_counts to slice flat_ids into per-seed groups - # and assign local indices. Example: - # - # 4 seeds, valid_counts = [1, 6, 2, 1] (10 total pairs) - # flat_ids = [d0a, d1a, d1b, d1c, d1d, d1e, d1f, d2a, d2b, d3a] - # - # seed 0 owns flat_ids[0:1], seed 1 owns flat_ids[1:7], - # seed 2 owns flat_ids[7:9], seed 3 owns flat_ids[9:10] - # _node_type_to_edge_types only contains source types; destination-only - # types are absent but may have accumulated PPR scores during the walk. - # We union with all types seen in ppr_scores so they appear in the output. - all_node_types: set[NodeType] = set(self._node_type_to_edge_types.keys()) - for seed_ppr in ppr_scores: - all_node_types.update(seed_ppr.keys()) + ppr_state.push_residuals(fetched_by_etype_id) + # Translate ntype_id integer keys back to NodeType strings for the rest + # of the pipeline, and move tensors to the correct device. ntype_to_flat_ids: dict[NodeType, torch.Tensor] = {} ntype_to_flat_weights: dict[NodeType, torch.Tensor] = {} ntype_to_valid_counts: dict[NodeType, torch.Tensor] = {} - for ntype in all_node_types: - flat_ids: list[int] = [] - flat_weights: list[float] = [] - valid_counts: list[int] = [] - - for i in range(batch_size): - type_scores = ppr_scores[i].get(ntype, {}) - top_k = heapq.nlargest( - self._max_ppr_nodes, type_scores.items(), key=lambda x: x[1] - ) - if top_k: - ids, weights = zip(*top_k) - flat_ids.extend(ids) - flat_weights.extend(weights) - valid_counts.append(len(top_k)) - - ntype_to_flat_ids[ntype] = torch.tensor( - flat_ids, dtype=torch.long, device=device - ) - ntype_to_flat_weights[ntype] = torch.tensor( - flat_weights, dtype=torch.float, device=device - ) - ntype_to_valid_counts[ntype] = torch.tensor( - valid_counts, dtype=torch.long, device=device - ) + for ntype_id, (flat_ids, flat_weights, valid_counts) in ppr_state.extract_top_k( + self._max_ppr_nodes + ).items(): + ntype = self._ntype_id_to_ntype[ntype_id] + ntype_to_flat_ids[ntype] = flat_ids.to(device) + ntype_to_flat_weights[ntype] = flat_weights.to(device) + ntype_to_valid_counts[ntype] = valid_counts.to(device) if self._is_homogeneous: assert ( From a23179686c7025a9e8428267743a036f0b532e63 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 24 Mar 2026 21:07:02 +0000 Subject: [PATCH 011/148] small precision fix --- .../cpp_extensions/ppr_forward_push.cpp | 35 ++++++++++--------- .../unit/distributed/dist_ppr_sampler_test.py | 13 ++++--- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp index 6f6d10545..e50373dcd 100644 --- a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp +++ b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp @@ -33,14 +33,14 @@ class PPRForwardPushState { PPRForwardPushState( torch::Tensor seed_nodes, int32_t seed_node_type_id, - float alpha, - float requeue_threshold_factor, + double alpha, + double requeue_threshold_factor, std::vector> node_type_to_edge_type_ids, std::vector edge_type_to_dst_ntype_id, std::vector degree_tensors ) : alpha_(alpha), - one_minus_alpha_(1.0f - alpha), + one_minus_alpha_(1.0 - alpha), requeue_threshold_factor_(requeue_threshold_factor), node_type_to_edge_type_ids_(std::move(node_type_to_edge_type_ids)), edge_type_to_dst_ntype_id_(std::move(edge_type_to_dst_ntype_id)), @@ -50,8 +50,8 @@ class PPRForwardPushState { batch_size_ = static_cast(seed_nodes.size(0)); num_node_types_ = static_cast(node_type_to_edge_type_ids_.size()); - ppr_scores_.assign(batch_size_, std::vector>(num_node_types_)); - residuals_.assign(batch_size_, std::vector>(num_node_types_)); + ppr_scores_.assign(batch_size_, std::vector>(num_node_types_)); + residuals_.assign(batch_size_, std::vector>(num_node_types_)); queue_.assign(batch_size_, std::vector>(num_node_types_)); queued_nodes_.assign(batch_size_, std::vector>(num_node_types_)); @@ -148,15 +148,15 @@ class PPRForwardPushState { for (int32_t src : queued_nodes_[s][nt]) { auto& src_res = residuals_[s][nt]; auto it = src_res.find(src); - float res = (it != src_res.end()) ? it->second : 0.0f; + double res = (it != src_res.end()) ? it->second : 0.0; ppr_scores_[s][nt][src] += res; - src_res[src] = 0.0f; + src_res[src] = 0.0; int32_t total_deg = get_total_degree(src, nt); if (total_deg == 0) continue; - float res_per_nbr = one_minus_alpha_ * res / static_cast(total_deg); + double res_per_nbr = one_minus_alpha_ * res / static_cast(total_deg); for (int32_t eid : node_type_to_edge_type_ids_[nt]) { // fetched and neighbor_cache are mutually exclusive per iteration: @@ -177,8 +177,8 @@ class PPRForwardPushState { for (int32_t nbr : *nbr_list) { residuals_[s][dst_nt][nbr] += res_per_nbr; - float threshold = requeue_threshold_factor_ * - static_cast(get_total_degree(nbr, dst_nt)); + double threshold = requeue_threshold_factor_ * + static_cast(get_total_degree(nbr, dst_nt)); if (queue_[s][dst_nt].find(nbr) == queue_[s][dst_nt].end() && residuals_[s][dst_nt][nbr] >= threshold) { @@ -225,12 +225,12 @@ class PPRForwardPushState { const auto& scores = ppr_scores_[s][nt]; int32_t k = std::min(max_ppr_nodes, static_cast(scores.size())); if (k > 0) { - std::vector> items(scores.begin(), scores.end()); + std::vector> items(scores.begin(), scores.end()); std::partial_sort(items.begin(), items.begin() + k, items.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); for (int32_t i = 0; i < k; ++i) { flat_ids.push_back(static_cast(items[i].first)); - flat_weights.push_back(items[i].second); + flat_weights.push_back(static_cast(items[i].second)); } } valid_counts.push_back(static_cast(k)); @@ -258,7 +258,7 @@ class PPRForwardPushState { return t.data_ptr()[node_id]; } - float alpha_, one_minus_alpha_, requeue_threshold_factor_; + double alpha_, one_minus_alpha_, requeue_threshold_factor_; int32_t batch_size_, num_node_types_, num_nodes_in_queue_{0}; std::vector> node_type_to_edge_type_ids_; @@ -266,8 +266,11 @@ class PPRForwardPushState { std::vector degree_tensors_; // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]). - std::vector>> ppr_scores_; - std::vector>> residuals_; + // double precision avoids float32 rounding errors accumulating over 20-30 + // push iterations, which would otherwise cause ~1e-4 score errors vs the + // true PPR. Output weights are cast to float32 in extract_top_k. + std::vector>> ppr_scores_; + std::vector>> residuals_; std::vector>> queue_; // Snapshot of queue contents from the last drain_queue() call, used by push_residuals(). std::vector>> queued_nodes_; @@ -283,7 +286,7 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { .def(py::init< torch::Tensor, int32_t, - float, float, + double, double, std::vector>, std::vector, std::vector diff --git a/tests/unit/distributed/dist_ppr_sampler_test.py b/tests/unit/distributed/dist_ppr_sampler_test.py index 5ad96e66e..a4f6d160b 100644 --- a/tests/unit/distributed/dist_ppr_sampler_test.py +++ b/tests/unit/distributed/dist_ppr_sampler_test.py @@ -270,8 +270,9 @@ def _assert_ppr_scores_match_reference( """Assert sampler PPR scores match reference scores per node type. Checks that top-k node sets are identical and that per-node scores - are within atol=1e-6. The forward push error per node is bounded by - O(alpha * eps * degree); observed deltas are ~1e-7 for eps=1e-6. + are within atol=1e-5. The forward push error per node is bounded by + O(alpha * eps * degree); for max degree 3, alpha=0.5, eps=1e-6 the + theoretical bound is ~1.5e-6, so 1e-5 provides a safety margin. Args: ntype_to_sampler_ppr: Sampler output from :func:`_extract_hetero_ppr_scores`. @@ -290,7 +291,7 @@ def _assert_ppr_scores_match_reference( for node_id in reference_ppr[ntype_str]: ref_score = reference_ppr[ntype_str][node_id] sam_score = ntype_to_sampler_ppr[ntype_str][node_id] - assert abs(sam_score - ref_score) < 1e-6, ( + assert abs(sam_score - ref_score) < 1e-5, ( f"{seed_id}, type {ntype_str}, node {node_id}: " f"sampler={sam_score:.8f} vs reference={ref_score:.8f}" ) @@ -372,11 +373,13 @@ def _run_ppr_loader_correctness_check( ) # Forward push is an approximation; with eps=1e-6 the per-node error - # is bounded by O(alpha * eps * degree). Observed deltas are ~1e-7. + # is bounded by O(alpha * eps * degree). For this test graph + # (max degree 3, alpha=0.5, eps=1e-6) the theoretical bound is ~1.5e-6. + # Tolerance is set to 1e-5 to provide a safety margin above that bound. for node_id in reference_ppr: ref_score = reference_ppr[node_id] sam_score = sampler_ppr[node_id] - assert abs(sam_score - ref_score) < 1e-6, ( + assert abs(sam_score - ref_score) < 1e-5, ( f"Seed {seed_global_id}, node {node_id}: " f"sampler={sam_score:.8f} vs reference={ref_score:.8f}" ) From a19db887809278de0de5427be033798031ddb41b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 24 Mar 2026 21:36:32 +0000 Subject: [PATCH 012/148] Optimize --- gigl/distributed/dist_ppr_sampler.py | 118 ++++++--------------------- 1 file changed, 24 insertions(+), 94 deletions(-) diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index cf4c732c0..b63329357 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -41,49 +41,6 @@ ) -def _group_fetched_by_etype_id( - fetched: dict[tuple[int, EdgeType], list[int]], - etype_to_etype_id: dict[EdgeType, int], -) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: - """Group batch-fetched neighbors by integer edge type ID for the C++ push kernel. - - Performs one linear pass over the fetched dict, building flat tensors per - edge type. This avoids per-neighbor Python overhead in push_residuals by - batching all lookups for the same edge type together. - - Args: - fetched: Output of _batch_fetch_neighbors: ``(node_id, etype)`` → - neighbor list. - etype_to_etype_id: Mapping from EdgeType to its integer ID. - - Returns: - Dict mapping etype_id to ``(node_ids, flat_neighbors, counts)`` as - flat int64 tensors. ``flat_neighbors`` is the concatenation of all - neighbor lists for that edge type; ``counts[i]`` gives the neighbor - count for ``node_ids[i]``. - """ - node_ids_by_etype: dict[int, list[int]] = {} - flat_nbrs_by_etype: dict[int, list[int]] = {} - counts_by_etype: dict[int, list[int]] = {} - for (node_id, etype), neighbors in fetched.items(): - eid = etype_to_etype_id[etype] - if eid not in node_ids_by_etype: - node_ids_by_etype[eid] = [] - flat_nbrs_by_etype[eid] = [] - counts_by_etype[eid] = [] - node_ids_by_etype[eid].append(node_id) - flat_nbrs_by_etype[eid].extend(neighbors) - counts_by_etype[eid].append(len(neighbors)) - return { - eid: ( - torch.tensor(node_ids_by_etype[eid], dtype=torch.long), - torch.tensor(flat_nbrs_by_etype[eid], dtype=torch.long), - torch.tensor(counts_by_etype[eid], dtype=torch.long), - ) - for eid in node_ids_by_etype - } - - # TODO (mkolodner-sc): Consider introducing a BaseGiGLSampler that owns # shared utilities like _prepare_sample_loop_inputs, with KHopSampler and # PPRSampler as siblings. Currently DistPPRNeighborSampler inherits from @@ -195,7 +152,7 @@ def __init__( # Build integer ID mappings for the C++ forward-push kernel. String # NodeType / EdgeType keys are only used at the Python boundary - # (translating to/from _batch_fetch_neighbors); all hot-loop state inside + # (translating to/from _sample_one_hop); all hot-loop state inside # PPRForwardPushState is indexed by int32 IDs. # # We include both source types (have outgoing edges) and destination-only @@ -301,68 +258,50 @@ def _get_destination_type(self, edge_type: EdgeType) -> NodeType: async def _batch_fetch_neighbors( self, - nodes_to_lookup: dict[EdgeType, set[int]], + nodes_by_etype_id: dict[int, torch.Tensor], device: torch.device, - ) -> dict[tuple[int, EdgeType], list[int]]: - """Batch fetch neighbors for nodes grouped by edge type. + ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: + """Batch fetch neighbors for nodes grouped by integer edge type ID. Issues one ``_sample_one_hop`` call per edge type (not per node), so all nodes of the same edge type are fetched in a single RPC round-trip. Each node's neighbor list is capped at ``self._num_neighbors_per_hop``. Args: - nodes_to_lookup: Dict mapping each edge type to the set of node IDs - whose neighbors should be fetched via that edge type. Only nodes - absent from the caller's ``neighbor_cache`` should be included. + nodes_by_etype_id: Dict mapping integer edge type ID to a 1-D int64 + tensor of node IDs to fetch neighbors for. Comes directly from + ``drain_queue()``; node IDs are already deduplicated. device: Torch device for intermediate tensor creation. Returns: - Dict mapping ``(node_id, edge_type)`` to the list of neighbor node IDs - returned by ``_sample_one_hop``. Only nodes that appeared in - ``nodes_to_lookup`` are present; edge types with an empty node set are - skipped entirely. + Dict mapping etype_id to ``(node_ids, flat_neighbors, counts)`` as + int64 tensors, ready to pass directly to ``push_residuals``. + ``flat_neighbors`` is the flat concatenation of all neighbor lists + for that edge type; ``counts[i]`` is the neighbor count for + ``node_ids[i]``. Example:: - nodes_to_lookup = { - ("user", "buys", "item"): {0, 3}, - ("item", "bought_by", "user"): {7}, + nodes_by_etype_id = { + 2: tensor([0, 3]), # etype_id 2 → nodes 0 and 3 + 5: tensor([7]), # etype_id 5 → node 7 } # Might return (neighbor lists depend on graph structure): { - (0, ("user", "buys", "item")): [5, 9, 2], - (3, ("user", "buys", "item")): [1], - (7, ("item", "bought_by", "user")): [0, 3], + 2: (tensor([0, 3]), tensor([5, 9, 2, 1]), tensor([3, 1])), + 5: (tensor([7]), tensor([0, 3]), tensor([2])), } """ - result: dict[tuple[int, EdgeType], list[int]] = {} - for etype, node_ids in nodes_to_lookup.items(): - if not node_ids: - continue - nodes_list = list(node_ids) - lookup_tensor = torch.tensor(nodes_list, dtype=torch.long, device=device) - + result: dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]] = {} + for eid, node_ids_tensor in nodes_by_etype_id.items(): + etype = self._etype_id_to_etype[eid] # _sample_one_hop expects None for homogeneous graphs, not the PPR sentinel. output: NeighborOutput = await self._sample_one_hop( - srcs=lookup_tensor, + srcs=node_ids_tensor.to(device), num_nbr=self._num_neighbors_per_hop, etype=etype if etype != _PPR_HOMOGENEOUS_EDGE_TYPE else None, ) - neighbors = output.nbr - neighbor_counts = output.nbr_num - - # TODO (mkolodner-sc): Investigate performance of a vectorized version of the below code - neighbors_list = neighbors.tolist() - counts_list = neighbor_counts.tolist() - del neighbors, neighbor_counts - - # neighbors_list is a flat concatenation of all neighbors for all looked-up nodes. - # We use offset to slice out each node's neighbors: node i's neighbors are at - # neighbors_list[offset : offset + count], then we advance offset by count. - offset = 0 - for node_id, count in zip(nodes_list, counts_list): - result[(node_id, etype)] = neighbors_list[offset : offset + count] - offset += count + result[eid] = (node_ids_tensor, output.nbr, output.nbr_num) return result @@ -449,17 +388,8 @@ async def _compute_ppr_scores( nodes_by_etype_id: dict[int, torch.Tensor] = drain_result if nodes_by_etype_id: - # Translate integer etype IDs back to EdgeType for the distributed - # fetch layer. O(num_active_etypes) — negligible vs. RPC round-trip. - nodes_to_lookup: dict[EdgeType, set[int]] = { - self._etype_id_to_etype[eid]: set(t.tolist()) - for eid, t in nodes_by_etype_id.items() - } - fetched_neighbors = await self._batch_fetch_neighbors( - nodes_to_lookup, device - ) - fetched_by_etype_id = _group_fetched_by_etype_id( - fetched_neighbors, self._etype_to_etype_id + fetched_by_etype_id = await self._batch_fetch_neighbors( + nodes_by_etype_id, device ) else: fetched_by_etype_id = {} From fed381545fc7923d7377b69513480e615057a588 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 24 Mar 2026 21:42:45 +0000 Subject: [PATCH 013/148] Add explanatory comments to ppr_forward_push.cpp for C++ newcomers --- .../cpp_extensions/ppr_forward_push.cpp | 244 +++++++++++++++--- 1 file changed, 203 insertions(+), 41 deletions(-) diff --git a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp index e50373dcd..e22ac264f 100644 --- a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp +++ b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp @@ -1,16 +1,30 @@ -#include -#include +#include // PyTorch C++ API (tensors, TORCH_CHECK) +#include // Automatic conversion between C++ containers and Python types -#include -#include -#include -#include -#include +#include // std::partial_sort, std::min +#include // Fixed-width integer types: int32_t, int64_t, uint32_t, uint64_t +#include // std::unordered_map — like Python dict, O(1) average lookup +#include // std::unordered_set — like Python set, O(1) average lookup +#include // std::vector — like Python list, contiguous in memory -namespace py = pybind11; +namespace py = pybind11; // Alias for the pybind11 namespace (bridges C++ ↔ Python) -// Pack (node_id, etype_id) into a single uint64_t lookup key. -// Requires both values fit in 32 bits — enforced by the Python caller. +// Combine (node_id, etype_id) into a single 64-bit integer for use as a hash +// map key. A single 64-bit integer is cheaper to hash than a pair of two +// integers (std::unordered_map has no built-in pair hash). +// +// Bit layout: +// bits 63–32: node_id (upper half) +// bits 31– 0: etype_id (lower half) +// +// Both inputs are cast through uint32_t before packing. Without this, a +// negative int32_t (e.g. -1 = 0xFFFFFFFF) would be sign-extended to a full +// 64-bit value, corrupting the upper bits when shifted. Reinterpreting as +// uint32_t first treats the bit pattern as-is (no sign extension). +// +// `static inline` means: define this function here in the translation unit +// (not in a separate object file) and ask the compiler to inline it at each +// call site instead of generating a function call. static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { return (static_cast(static_cast(node_id)) << 32) | static_cast(etype_id); @@ -18,6 +32,10 @@ static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { // C++ kernel for the PPR Forward Push algorithm (Andersen et al., 2006). // +// All hot-loop state (scores, residuals, queue, neighbor cache) lives inside +// this object. The distributed neighbor fetch is kept in Python because it +// involves async RPC calls that C++ cannot drive directly. +// // Owned state: ppr_scores, residuals, queue, queued_nodes, neighbor_cache. // Python retains ownership of: the distributed neighbor fetch (_batch_fetch_neighbors). // @@ -42,6 +60,9 @@ class PPRForwardPushState { : alpha_(alpha), one_minus_alpha_(1.0 - alpha), requeue_threshold_factor_(requeue_threshold_factor), + // std::move transfers ownership of each vector into the member variable + // without copying its contents — equivalent to Python's list hand-off + // when you no longer need the original. node_type_to_edge_type_ids_(std::move(node_type_to_edge_type_ids)), edge_type_to_dst_ntype_id_(std::move(edge_type_to_dst_ntype_id)), degree_tensors_(std::move(degree_tensors)) { @@ -50,15 +71,26 @@ class PPRForwardPushState { batch_size_ = static_cast(seed_nodes.size(0)); num_node_types_ = static_cast(node_type_to_edge_type_ids_.size()); - ppr_scores_.assign(batch_size_, std::vector>(num_node_types_)); - residuals_.assign(batch_size_, std::vector>(num_node_types_)); - queue_.assign(batch_size_, std::vector>(num_node_types_)); - queued_nodes_.assign(batch_size_, std::vector>(num_node_types_)); - + // Allocate per-seed, per-node-type tables. + // .assign(n, val) fills a vector with n copies of val — like [val] * n in Python. + // Each inner element is an empty hash map / hash set for that (seed, ntype) pair. + ppr_scores_.assign(batch_size_, std::vector>(num_node_types_)); + residuals_.assign(batch_size_, std::vector>(num_node_types_)); + queue_.assign(batch_size_, std::vector>(num_node_types_)); + queued_nodes_.assign(batch_size_, std::vector>(num_node_types_)); + + // accessor() returns a typed view into the tensor's data that + // supports [i] indexing with bounds checking in debug builds. Here we read + // each seed node ID from the 1-D int64 tensor. auto acc = seed_nodes.accessor(); num_nodes_in_queue_ = batch_size_; for (int32_t i = 0; i < batch_size_; ++i) { + // static_cast: explicit narrowing from int64 to int32. + // The Python caller guarantees node IDs fit in 32 bits. int32_t seed = static_cast(acc[i]); + // PPR initialisation: each seed starts with residual = alpha (the + // restart probability). The first push will move alpha into ppr_score + // and distribute (1-alpha)*alpha to the seed's neighbors. residuals_[i][seed_node_type_id][seed] = alpha_; queue_[i][seed_node_type_id].insert(seed); } @@ -68,32 +100,45 @@ class PPRForwardPushState { // neighbor lookup. Also snapshots the drained nodes into queued_nodes_ for // use by push_residuals(). // - // Returns None when the queue is truly empty (convergence signal). - // Returns a dict (possibly empty) when nodes were drained but all had cached - // neighbors or no outgoing edges — push_residuals must still be called to - // flush their residuals into ppr_scores_. + // Return value semantics (py::object can hold any Python value): + // - py::none() → queue was already empty; convergence achieved; stop the loop. + // - py::dict{} → nodes were drained. The dict maps etype_id → 1-D int64 + // tensor of node IDs that need neighbor lookups this round. + // May be empty if all drained nodes were already in the cache + // or had no outgoing edges — push_residuals must still be called + // to flush their accumulated residual into ppr_scores_. py::object drain_queue() { if (num_nodes_in_queue_ == 0) { return py::none(); } + // Reset the snapshot from the previous iteration. `auto&` is a reference + // (alias) to the existing set — clearing it modifies the original in-place + // rather than operating on a copy. for (int32_t s = 0; s < batch_size_; ++s) for (auto& qs : queued_nodes_[s]) qs.clear(); + // nodes_to_lookup[eid] = set of node IDs that need a neighbor fetch for + // edge type eid this round. Using a set deduplicates nodes that appear + // in multiple seeds' queues: we only fetch each (node, etype) pair once + // regardless of how many seeds need it. std::unordered_map> nodes_to_lookup; for (int32_t s = 0; s < batch_size_; ++s) { for (int32_t nt = 0; nt < num_node_types_; ++nt) { if (queue_[s][nt].empty()) continue; - // Snapshot queue into queued_nodes, then reset queue. + // Move the live queue into the snapshot (no data copy — O(1)). + // queue_ is then reset to an empty set so new entries added by + // push_residuals() in this same iteration don't interfere. queued_nodes_[s][nt] = std::move(queue_[s][nt]); queue_[s][nt].clear(); num_nodes_in_queue_ -= static_cast(queued_nodes_[s][nt].size()); for (int32_t node_id : queued_nodes_[s][nt]) { for (int32_t eid : node_type_to_edge_type_ids_[nt]) { - // Only add to lookup if not already in the persistent cache. + // Only request a fetch if the neighbor list isn't already + // cached from a previous iteration. if (neighbor_cache_.find(pack_key(node_id, eid)) == neighbor_cache_.end()) { nodes_to_lookup[eid].insert(node_id); } @@ -102,8 +147,13 @@ class PPRForwardPushState { } } + // Convert to Python: {etype_id (int) → 1-D int64 tensor of node IDs}. + // py::int_(eid) wraps a C++ int as a Python int so it can be used as a + // dict key on the Python side. py::dict result; for (auto& [eid, node_set] : nodes_to_lookup) { + // Copy the set into a vector first: torch::tensor() requires a + // contiguous sequence, not an unordered_set iterator. std::vector ids(node_set.begin(), node_set.end()); result[py::int_(eid)] = torch::tensor(ids, torch::kLong); } @@ -111,24 +161,38 @@ class PPRForwardPushState { } // Push residuals to neighbors given the fetched neighbor data. + // // fetched_by_etype_id: {etype_id: (node_ids_tensor, flat_nbrs_tensor, counts_tensor)} - // - node_ids_tensor: [N] int64 — source node IDs fetched for this edge type - // - flat_nbrs_tensor: [sum(counts)] int64 — flat concatenation of all neighbor lists - // - counts_tensor: [N] int64 — number of neighbors for each source node + // - node_ids_tensor: [N] int64 — source node IDs fetched for this edge type + // - flat_nbrs_tensor: [sum(counts)] int64 — all neighbor lists concatenated flat + // - counts_tensor: [N] int64 — neighbor count for each source node + // + // For example, if nodes 3 and 7 were fetched for etype 0: + // node_ids = [3, 7] + // flat_nbrs = [10, 11, 12, 20] ← node 3 has nbrs {10,11,12}, node 7 has nbr {20} + // counts = [3, 1] void push_residuals(py::dict fetched_by_etype_id) { - // Build local fetched map: pack_key(node_id, etype_id) -> neighbor list. + // Step 1: Unpack the Python dict into a C++ map for fast lookup during + // the residual-push loop below. + // fetched: pack_key(node_id, etype_id) → neighbor list (as int32_t vector) std::unordered_map> fetched; for (auto item : fetched_by_etype_id) { - int32_t eid = item.first.cast(); + int32_t eid = item.first.cast(); + // .cast() interprets the Python value as a tuple so we + // can index into it with [0], [1], [2]. auto tup = item.second.cast(); auto node_ids_t = tup[0].cast(); auto flat_nbrs_t = tup[1].cast(); auto counts_t = tup[2].cast(); - auto node_acc = node_ids_t.accessor(); - auto nbr_acc = flat_nbrs_t.accessor(); - auto cnt_acc = counts_t.accessor(); + // accessor() gives a bounds-checked, typed 1-D view into + // each tensor's data — equivalent to iterating over a NumPy array. + auto node_acc = node_ids_t.accessor(); + auto nbr_acc = flat_nbrs_t.accessor(); + auto cnt_acc = counts_t.accessor(); + // Walk the flat neighbor list, slicing out each node's neighbors using + // the running offset into the concatenated flat buffer. int64_t offset = 0; for (int64_t i = 0; i < node_ids_t.size(0); ++i) { int32_t nid = static_cast(node_acc[i]); @@ -136,54 +200,85 @@ class PPRForwardPushState { std::vector nbrs(count); for (int64_t j = 0; j < count; ++j) nbrs[j] = static_cast(nbr_acc[offset + j]); + // std::move: hand off nbrs to the map without copying its contents. fetched[pack_key(nid, eid)] = std::move(nbrs); offset += count; } } + // Step 2: For every node that was in the queue (captured in queued_nodes_ + // by drain_queue()), apply one PPR push step: + // a. Absorb residual into the PPR score. + // b. Distribute (1-alpha) * residual equally to each neighbor. + // c. Enqueue any neighbor whose residual now exceeds the requeue threshold. for (int32_t s = 0; s < batch_size_; ++s) { for (int32_t nt = 0; nt < num_node_types_; ++nt) { if (queued_nodes_[s][nt].empty()) continue; for (int32_t src : queued_nodes_[s][nt]) { + // `auto&` gives a reference to the residual map for this + // (seed, node_type) pair so we can read and write it without + // an extra hash lookup each time. auto& src_res = residuals_[s][nt]; + // .find() returns an iterator; .end() means "not found". + // We treat a missing entry as residual = 0. auto it = src_res.find(src); double res = (it != src_res.end()) ? it->second : 0.0; + // a. Absorb: move residual into the PPR score. ppr_scores_[s][nt][src] += res; src_res[src] = 0.0; int32_t total_deg = get_total_degree(src, nt); + // Destination-only nodes (no outgoing edges) absorb residual + // into their PPR score but do not push further. if (total_deg == 0) continue; + // b. Distribute: each neighbor of src (across all edge types + // from nt) receives an equal share of the pushed residual. double res_per_nbr = one_minus_alpha_ * res / static_cast(total_deg); for (int32_t eid : node_type_to_edge_type_ids_[nt]) { - // fetched and neighbor_cache are mutually exclusive per iteration: - // drain_queue only adds a node to nodes_to_lookup when absent from - // neighbor_cache, so a given key appears in at most one of the two. + // Invariant: fetched and neighbor_cache_ are mutually exclusive for + // any given (node, etype) key within one iteration. drain_queue() + // only requests a fetch for nodes absent from neighbor_cache_, so a + // key is in at most one of the two. We check fetched first since it + // is the common case for newly-seen nodes. + // + // `const std::vector*` is a pointer to a neighbor list. + // We use a pointer (rather than copying the list) so we can check + // for absence with nullptr without allocating anything. const std::vector* nbr_list = nullptr; auto fi = fetched.find(pack_key(src, eid)); if (fi != fetched.end()) { + // `&fi->second` takes the address of the vector stored in + // the map — nbr_list now points to it without copying. nbr_list = &fi->second; } else { auto ci = neighbor_cache_.find(pack_key(src, eid)); if (ci != neighbor_cache_.end()) nbr_list = &ci->second; } + // Skip if no neighbor list is available (node has no edges of + // this type, or the fetch returned an empty list). if (!nbr_list || nbr_list->empty()) continue; int32_t dst_nt = edge_type_to_dst_ntype_id_[eid]; + // c. For each neighbor, accumulate residual and check threshold. + // `*nbr_list` dereferences the pointer to access the vector. for (int32_t nbr : *nbr_list) { residuals_[s][dst_nt][nbr] += res_per_nbr; double threshold = requeue_threshold_factor_ * static_cast(get_total_degree(nbr, dst_nt)); + // Only enqueue if: (1) not already in queue for this + // iteration, and (2) residual exceeds the push threshold + // alpha * eps * degree. if (queue_[s][dst_nt].find(nbr) == queue_[s][dst_nt].end() && residuals_[s][dst_nt][nbr] >= threshold) { queue_[s][dst_nt].insert(nbr); - ++num_nodes_in_queue_; + ++num_nodes_in_queue_; // ++x is equivalent to x += 1 // Promote this node's neighbor lists to the persistent cache: // it will be processed next iteration, so caching now avoids @@ -207,9 +302,16 @@ class PPRForwardPushState { } // Extract top-k PPR nodes per seed per node type. + // // Returns {ntype_id: (flat_ids_tensor, flat_weights_tensor, valid_counts_tensor)}. // Only node types that received any PPR score are included in the output. + // + // Output layout for a batch of B seeds (same structure as _batch_fetch_neighbors): + // flat_ids[0 : valid_counts[0]] → top-k nodes for seed 0 + // flat_ids[valid_counts[0] : valid_counts[0]+valid_counts[1]] → top-k for seed 1 + // ... py::dict extract_top_k(int32_t max_ppr_nodes) { + // Collect node types that have any PPR score — skip types with no activity. std::unordered_set active; for (int32_t s = 0; s < batch_size_; ++s) for (int32_t nt = 0; nt < num_node_types_; ++nt) @@ -217,25 +319,42 @@ class PPRForwardPushState { py::dict result; for (int32_t nt : active) { + // Flat output vectors — entries for all seeds are concatenated. std::vector flat_ids; std::vector flat_weights; std::vector valid_counts; for (int32_t s = 0; s < batch_size_; ++s) { + // `const auto&` is a read-only reference — we iterate the map + // without copying it. const auto& scores = ppr_scores_[s][nt]; + // Cap k at the number of nodes that actually have a score. int32_t k = std::min(max_ppr_nodes, static_cast(scores.size())); if (k > 0) { + // Copy the map entries into a vector of (node_id, score) pairs + // so they can be sorted. std::pair is like a Python 2-tuple. std::vector> items(scores.begin(), scores.end()); + + // std::partial_sort rearranges items so that the first k entries + // are the k largest — like Python's heapq.nlargest but in-place. + // The lambda `[](const auto& a, const auto& b) { return ...; }` + // is an anonymous comparator (like Python's `key=` argument). + // `.second` accesses the score (second element of the pair); + // `>` makes it descending (highest score first). std::partial_sort(items.begin(), items.begin() + k, items.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); + for (int32_t i = 0; i < k; ++i) { flat_ids.push_back(static_cast(items[i].first)); + // Cast to float32 for output; internal scores stay double to + // avoid accumulated rounding errors in the push loop above. flat_weights.push_back(static_cast(items[i].second)); } } valid_counts.push_back(static_cast(k)); } + // py::make_tuple wraps C++ values into a Python tuple. result[py::int_(nt)] = py::make_tuple( torch::tensor(flat_ids, torch::kLong), torch::tensor(flat_weights, torch::kFloat), @@ -246,6 +365,8 @@ class PPRForwardPushState { } private: + // Look up the total (across all edge types) out-degree of a node. + // Returns 0 for destination-only node types (no outgoing edges). int32_t get_total_degree(int32_t node_id, int32_t ntype_id) const { if (ntype_id >= static_cast(degree_tensors_.size())) return 0; const auto& t = degree_tensors_[ntype_id]; @@ -255,34 +376,75 @@ class PPRForwardPushState { "Node ID ", node_id, " out of range for degree tensor of ntype_id ", ntype_id, " (size=", t.size(0), "). This indicates corrupted graph data or a sampler bug." ); + // data_ptr() returns a raw C pointer to the tensor's int32 data + // buffer. Direct pointer indexing ([node_id]) is safe here because we + // validated the bounds with TORCH_CHECK above. return t.data_ptr()[node_id]; } - double alpha_, one_minus_alpha_, requeue_threshold_factor_; - int32_t batch_size_, num_node_types_, num_nodes_in_queue_{0}; - + // ------------------------------------------------------------------------- + // Scalar algorithm parameters + // ------------------------------------------------------------------------- + double alpha_; // Restart probability + double one_minus_alpha_; // 1 - alpha, precomputed to avoid repeated subtraction + double requeue_threshold_factor_; // alpha * eps; multiplied by degree to get per-node threshold + + int32_t batch_size_; // Number of seeds in the current batch + int32_t num_node_types_; // Total number of node types (homo + hetero) + int32_t num_nodes_in_queue_{0}; // Running count of nodes across all seeds / types + + // ------------------------------------------------------------------------- + // Graph structure (read-only after construction) + // ------------------------------------------------------------------------- + // node_type_to_edge_type_ids_[ntype_id] → list of edge type IDs that can be + // traversed from that node type (outgoing or incoming, depending on edge_dir). std::vector> node_type_to_edge_type_ids_; + // edge_type_to_dst_ntype_id_[eid] → node type ID at the destination end. std::vector edge_type_to_dst_ntype_id_; + // degree_tensors_[ntype_id][node_id] → total degree of that node across all + // edge types traversable from its type. Empty tensor means no outgoing edges. std::vector degree_tensors_; - // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]). + // ------------------------------------------------------------------------- + // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]) + // ------------------------------------------------------------------------- // double precision avoids float32 rounding errors accumulating over 20-30 // push iterations, which would otherwise cause ~1e-4 score errors vs the // true PPR. Output weights are cast to float32 in extract_top_k. + // + // ppr_scores_[s][nt]: node_id → absorbed PPR score (Σ of residuals pushed so far) std::vector>> ppr_scores_; + // residuals_[s][nt]: node_id → unabsorbed probability mass waiting to be pushed std::vector>> residuals_; + // queue_[s][nt]: nodes whose residual exceeds the threshold and need a push next round std::vector>> queue_; - // Snapshot of queue contents from the last drain_queue() call, used by push_residuals(). + // queued_nodes_[s][nt]: snapshot of queue_ taken by drain_queue() for the current round. + // Separating it from queue_ lets push_residuals() enqueue new nodes into queue_ without + // modifying the set currently being iterated. std::vector>> queued_nodes_; - // Persistent neighbor cache: pack_key(node_id, etype_id) -> neighbor list. - // Only nodes that have been requeued (and thus will be processed again) are - // promoted here from the per-iteration fetched map. + // ------------------------------------------------------------------------- + // Neighbor cache + // ------------------------------------------------------------------------- + // Persistent cache: pack_key(node_id, etype_id) → neighbor list. + // Only nodes that have been re-queued (and will therefore be processed again) + // are promoted here from the per-iteration fetched map in push_residuals(). + // This avoids re-fetching neighbors for nodes processed in multiple iterations + // while keeping large neighbor lists of high-degree (never-requeued) nodes + // out of memory. std::unordered_map> neighbor_cache_; }; +// Register PPRForwardPushState with Python via pybind11. +// +// TORCH_EXTENSION_NAME is set by PyTorch's setup() at build time to match the +// Python module name (e.g. "ppr_forward_push"). At import time, Python calls +// this function to populate the module with the C++ class. PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { py::class_(m, "PPRForwardPushState") + // .def(py::init<...>()) exposes the constructor. The template arguments + // list the exact C++ parameter types so pybind11 can convert Python + // arguments to the correct C++ types automatically. .def(py::init< torch::Tensor, int32_t, From 906df014092f388eba9274121e6d838c81b8abdd Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 18:48:27 +0000 Subject: [PATCH 014/148] Apply clang-format to ppr_forward_push.cpp --- .../cpp_extensions/ppr_forward_push.cpp | 127 +++++++++--------- 1 file changed, 63 insertions(+), 64 deletions(-) diff --git a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp index e22ac264f..0af3eb2b5 100644 --- a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp +++ b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp @@ -1,8 +1,8 @@ +#include // Automatic conversion between C++ containers and Python types #include // PyTorch C++ API (tensors, TORCH_CHECK) -#include // Automatic conversion between C++ containers and Python types -#include // std::partial_sort, std::min -#include // Fixed-width integer types: int32_t, int64_t, uint32_t, uint64_t +#include // std::partial_sort, std::min +#include // Fixed-width integer types: int32_t, int64_t, uint32_t, uint64_t #include // std::unordered_map — like Python dict, O(1) average lookup #include // std::unordered_set — like Python set, O(1) average lookup #include // std::vector — like Python list, contiguous in memory @@ -47,16 +47,12 @@ static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { // 4. push_residuals(fetched_by_etype_id) — push residuals, update queue // 5. extract_top_k(max_ppr_nodes) — top-k selection per seed per node type class PPRForwardPushState { -public: - PPRForwardPushState( - torch::Tensor seed_nodes, - int32_t seed_node_type_id, - double alpha, - double requeue_threshold_factor, - std::vector> node_type_to_edge_type_ids, - std::vector edge_type_to_dst_ntype_id, - std::vector degree_tensors - ) + public: + PPRForwardPushState(torch::Tensor seed_nodes, int32_t seed_node_type_id, double alpha, + double requeue_threshold_factor, + std::vector> node_type_to_edge_type_ids, + std::vector edge_type_to_dst_ntype_id, + std::vector degree_tensors) : alpha_(alpha), one_minus_alpha_(1.0 - alpha), requeue_threshold_factor_(requeue_threshold_factor), @@ -66,7 +62,6 @@ class PPRForwardPushState { node_type_to_edge_type_ids_(std::move(node_type_to_edge_type_ids)), edge_type_to_dst_ntype_id_(std::move(edge_type_to_dst_ntype_id)), degree_tensors_(std::move(degree_tensors)) { - TORCH_CHECK(seed_nodes.dim() == 1, "seed_nodes must be 1D"); batch_size_ = static_cast(seed_nodes.size(0)); num_node_types_ = static_cast(node_type_to_edge_type_ids_.size()); @@ -74,15 +69,18 @@ class PPRForwardPushState { // Allocate per-seed, per-node-type tables. // .assign(n, val) fills a vector with n copies of val — like [val] * n in Python. // Each inner element is an empty hash map / hash set for that (seed, ntype) pair. - ppr_scores_.assign(batch_size_, std::vector>(num_node_types_)); - residuals_.assign(batch_size_, std::vector>(num_node_types_)); - queue_.assign(batch_size_, std::vector>(num_node_types_)); - queued_nodes_.assign(batch_size_, std::vector>(num_node_types_)); + ppr_scores_.assign(batch_size_, + std::vector>(num_node_types_)); + residuals_.assign(batch_size_, + std::vector>(num_node_types_)); + queue_.assign(batch_size_, std::vector>(num_node_types_)); + queued_nodes_.assign(batch_size_, + std::vector>(num_node_types_)); // accessor() returns a typed view into the tensor's data that // supports [i] indexing with bounds checking in debug builds. Here we read // each seed node ID from the 1-D int64 tensor. - auto acc = seed_nodes.accessor(); + auto acc = seed_nodes.accessor(); num_nodes_in_queue_ = batch_size_; for (int32_t i = 0; i < batch_size_; ++i) { // static_cast: explicit narrowing from int64 to int32. @@ -116,7 +114,8 @@ class PPRForwardPushState { // (alias) to the existing set — clearing it modifies the original in-place // rather than operating on a copy. for (int32_t s = 0; s < batch_size_; ++s) - for (auto& qs : queued_nodes_[s]) qs.clear(); + for (auto& qs : queued_nodes_[s]) + qs.clear(); // nodes_to_lookup[eid] = set of node IDs that need a neighbor fetch for // edge type eid this round. Using a set deduplicates nodes that appear @@ -126,7 +125,8 @@ class PPRForwardPushState { for (int32_t s = 0; s < batch_size_; ++s) { for (int32_t nt = 0; nt < num_node_types_; ++nt) { - if (queue_[s][nt].empty()) continue; + if (queue_[s][nt].empty()) + continue; // Move the live queue into the snapshot (no data copy — O(1)). // queue_ is then reset to an empty set so new entries added by @@ -213,7 +213,8 @@ class PPRForwardPushState { // c. Enqueue any neighbor whose residual now exceeds the requeue threshold. for (int32_t s = 0; s < batch_size_; ++s) { for (int32_t nt = 0; nt < num_node_types_; ++nt) { - if (queued_nodes_[s][nt].empty()) continue; + if (queued_nodes_[s][nt].empty()) + continue; for (int32_t src : queued_nodes_[s][nt]) { // `auto&` gives a reference to the residual map for this @@ -222,7 +223,7 @@ class PPRForwardPushState { auto& src_res = residuals_[s][nt]; // .find() returns an iterator; .end() means "not found". // We treat a missing entry as residual = 0. - auto it = src_res.find(src); + auto it = src_res.find(src); double res = (it != src_res.end()) ? it->second : 0.0; // a. Absorb: move residual into the PPR score. @@ -232,7 +233,8 @@ class PPRForwardPushState { int32_t total_deg = get_total_degree(src, nt); // Destination-only nodes (no outgoing edges) absorb residual // into their PPR score but do not push further. - if (total_deg == 0) continue; + if (total_deg == 0) + continue; // b. Distribute: each neighbor of src (across all edge types // from nt) receives an equal share of the pushed residual. @@ -249,18 +251,20 @@ class PPRForwardPushState { // We use a pointer (rather than copying the list) so we can check // for absence with nullptr without allocating anything. const std::vector* nbr_list = nullptr; - auto fi = fetched.find(pack_key(src, eid)); + auto fi = fetched.find(pack_key(src, eid)); if (fi != fetched.end()) { // `&fi->second` takes the address of the vector stored in // the map — nbr_list now points to it without copying. nbr_list = &fi->second; } else { auto ci = neighbor_cache_.find(pack_key(src, eid)); - if (ci != neighbor_cache_.end()) nbr_list = &ci->second; + if (ci != neighbor_cache_.end()) + nbr_list = &ci->second; } // Skip if no neighbor list is available (node has no edges of // this type, or the fetch returned an empty list). - if (!nbr_list || nbr_list->empty()) continue; + if (!nbr_list || nbr_list->empty()) + continue; int32_t dst_nt = edge_type_to_dst_ntype_id_[eid]; @@ -270,7 +274,7 @@ class PPRForwardPushState { residuals_[s][dst_nt][nbr] += res_per_nbr; double threshold = requeue_threshold_factor_ * - static_cast(get_total_degree(nbr, dst_nt)); + static_cast(get_total_degree(nbr, dst_nt)); // Only enqueue if: (1) not already in queue for this // iteration, and (2) residual exceeds the push threshold @@ -315,13 +319,14 @@ class PPRForwardPushState { std::unordered_set active; for (int32_t s = 0; s < batch_size_; ++s) for (int32_t nt = 0; nt < num_node_types_; ++nt) - if (!ppr_scores_[s][nt].empty()) active.insert(nt); + if (!ppr_scores_[s][nt].empty()) + active.insert(nt); py::dict result; for (int32_t nt : active) { // Flat output vectors — entries for all seeds are concatenated. std::vector flat_ids; - std::vector flat_weights; + std::vector flat_weights; std::vector valid_counts; for (int32_t s = 0; s < batch_size_; ++s) { @@ -341,7 +346,8 @@ class PPRForwardPushState { // is an anonymous comparator (like Python's `key=` argument). // `.second` accesses the score (second element of the pair); // `>` makes it descending (highest score first). - std::partial_sort(items.begin(), items.begin() + k, items.end(), + std::partial_sort( + items.begin(), items.begin() + k, items.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); for (int32_t i = 0; i < k; ++i) { @@ -355,27 +361,25 @@ class PPRForwardPushState { } // py::make_tuple wraps C++ values into a Python tuple. - result[py::int_(nt)] = py::make_tuple( - torch::tensor(flat_ids, torch::kLong), - torch::tensor(flat_weights, torch::kFloat), - torch::tensor(valid_counts, torch::kLong) - ); + result[py::int_(nt)] = py::make_tuple(torch::tensor(flat_ids, torch::kLong), + torch::tensor(flat_weights, torch::kFloat), + torch::tensor(valid_counts, torch::kLong)); } return result; } -private: + private: // Look up the total (across all edge types) out-degree of a node. // Returns 0 for destination-only node types (no outgoing edges). int32_t get_total_degree(int32_t node_id, int32_t ntype_id) const { - if (ntype_id >= static_cast(degree_tensors_.size())) return 0; + if (ntype_id >= static_cast(degree_tensors_.size())) + return 0; const auto& t = degree_tensors_[ntype_id]; - if (t.numel() == 0) return 0; // destination-only type: no outgoing edges - TORCH_CHECK( - node_id < static_cast(t.size(0)), - "Node ID ", node_id, " out of range for degree tensor of ntype_id ", ntype_id, - " (size=", t.size(0), "). This indicates corrupted graph data or a sampler bug." - ); + if (t.numel() == 0) + return 0; // destination-only type: no outgoing edges + TORCH_CHECK(node_id < static_cast(t.size(0)), "Node ID ", node_id, + " out of range for degree tensor of ntype_id ", ntype_id, " (size=", t.size(0), + "). This indicates corrupted graph data or a sampler bug."); // data_ptr() returns a raw C pointer to the tensor's int32 data // buffer. Direct pointer indexing ([node_id]) is safe here because we // validated the bounds with TORCH_CHECK above. @@ -385,13 +389,14 @@ class PPRForwardPushState { // ------------------------------------------------------------------------- // Scalar algorithm parameters // ------------------------------------------------------------------------- - double alpha_; // Restart probability - double one_minus_alpha_; // 1 - alpha, precomputed to avoid repeated subtraction - double requeue_threshold_factor_; // alpha * eps; multiplied by degree to get per-node threshold + double alpha_; // Restart probability + double one_minus_alpha_; // 1 - alpha, precomputed to avoid repeated subtraction + double + requeue_threshold_factor_; // alpha * eps; multiplied by degree to get per-node threshold - int32_t batch_size_; // Number of seeds in the current batch - int32_t num_node_types_; // Total number of node types (homo + hetero) - int32_t num_nodes_in_queue_{0}; // Running count of nodes across all seeds / types + int32_t batch_size_; // Number of seeds in the current batch + int32_t num_node_types_; // Total number of node types (homo + hetero) + int32_t num_nodes_in_queue_{0}; // Running count of nodes across all seeds / types // ------------------------------------------------------------------------- // Graph structure (read-only after construction) @@ -400,10 +405,10 @@ class PPRForwardPushState { // traversed from that node type (outgoing or incoming, depending on edge_dir). std::vector> node_type_to_edge_type_ids_; // edge_type_to_dst_ntype_id_[eid] → node type ID at the destination end. - std::vector edge_type_to_dst_ntype_id_; + std::vector edge_type_to_dst_ntype_id_; // degree_tensors_[ntype_id][node_id] → total degree of that node across all // edge types traversable from its type. Empty tensor means no outgoing edges. - std::vector degree_tensors_; + std::vector degree_tensors_; // ------------------------------------------------------------------------- // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]) @@ -417,11 +422,11 @@ class PPRForwardPushState { // residuals_[s][nt]: node_id → unabsorbed probability mass waiting to be pushed std::vector>> residuals_; // queue_[s][nt]: nodes whose residual exceeds the threshold and need a push next round - std::vector>> queue_; + std::vector>> queue_; // queued_nodes_[s][nt]: snapshot of queue_ taken by drain_queue() for the current round. // Separating it from queue_ lets push_residuals() enqueue new nodes into queue_ without // modifying the set currently being iterated. - std::vector>> queued_nodes_; + std::vector>> queued_nodes_; // ------------------------------------------------------------------------- // Neighbor cache @@ -445,15 +450,9 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { // .def(py::init<...>()) exposes the constructor. The template arguments // list the exact C++ parameter types so pybind11 can convert Python // arguments to the correct C++ types automatically. - .def(py::init< - torch::Tensor, - int32_t, - double, double, - std::vector>, - std::vector, - std::vector - >()) - .def("drain_queue", &PPRForwardPushState::drain_queue) + .def(py::init>, + std::vector, std::vector>()) + .def("drain_queue", &PPRForwardPushState::drain_queue) .def("push_residuals", &PPRForwardPushState::push_residuals) - .def("extract_top_k", &PPRForwardPushState::extract_top_k); + .def("extract_top_k", &PPRForwardPushState::extract_top_k); } From dd118ef09320b0afea72f79b93dbc3d691a6e4be Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 20:49:28 +0000 Subject: [PATCH 015/148] Move PPR C++ to gigl/csrc following PyTorch csrc conventions --- gigl/csrc/distributed/__init__.py | 9 + gigl/csrc/distributed/ppr_forward_push.cpp | 247 ++++++++++ gigl/csrc/distributed/ppr_forward_push.h | 121 +++++ .../distributed}/ppr_forward_push.pyi | 0 .../distributed/python_ppr_forward_push.cpp | 63 +++ gigl/distributed/cpp_extensions/__init__.py | 9 - .../cpp_extensions/ppr_forward_push.cpp | 458 ------------------ gigl/distributed/dist_ppr_sampler.py | 2 +- 8 files changed, 441 insertions(+), 468 deletions(-) create mode 100644 gigl/csrc/distributed/__init__.py create mode 100644 gigl/csrc/distributed/ppr_forward_push.cpp create mode 100644 gigl/csrc/distributed/ppr_forward_push.h rename gigl/{distributed/cpp_extensions => csrc/distributed}/ppr_forward_push.pyi (100%) create mode 100644 gigl/csrc/distributed/python_ppr_forward_push.cpp delete mode 100644 gigl/distributed/cpp_extensions/__init__.py delete mode 100644 gigl/distributed/cpp_extensions/ppr_forward_push.cpp diff --git a/gigl/csrc/distributed/__init__.py b/gigl/csrc/distributed/__init__.py new file mode 100644 index 000000000..d8ffa921a --- /dev/null +++ b/gigl/csrc/distributed/__init__.py @@ -0,0 +1,9 @@ +try: + from gigl.csrc.distributed.ppr_forward_push import PPRForwardPushState +except ImportError as e: + raise ImportError( + "PPR C++ extension not compiled. " + "Run `make build_cpp_extensions` from the GiGL root to build it." + ) from e + +__all__ = ["PPRForwardPushState"] diff --git a/gigl/csrc/distributed/ppr_forward_push.cpp b/gigl/csrc/distributed/ppr_forward_push.cpp new file mode 100644 index 000000000..a514907ab --- /dev/null +++ b/gigl/csrc/distributed/ppr_forward_push.cpp @@ -0,0 +1,247 @@ +#include "ppr_forward_push.h" + +PPRForwardPushState::PPRForwardPushState( + torch::Tensor seed_nodes, int32_t seed_node_type_id, double alpha, + double requeue_threshold_factor, + std::vector> node_type_to_edge_type_ids, + std::vector edge_type_to_dst_ntype_id, std::vector degree_tensors) + : alpha_(alpha), + one_minus_alpha_(1.0 - alpha), + requeue_threshold_factor_(requeue_threshold_factor), + // std::move transfers ownership of each vector into the member variable + // without copying its contents — equivalent to Python's list hand-off + // when you no longer need the original. + node_type_to_edge_type_ids_(std::move(node_type_to_edge_type_ids)), + edge_type_to_dst_ntype_id_(std::move(edge_type_to_dst_ntype_id)), + degree_tensors_(std::move(degree_tensors)) { + TORCH_CHECK(seed_nodes.dim() == 1, "seed_nodes must be 1D"); + batch_size_ = static_cast(seed_nodes.size(0)); + num_node_types_ = static_cast(node_type_to_edge_type_ids_.size()); + + // Allocate per-seed, per-node-type tables. + // .assign(n, val) fills a vector with n copies of val — like [val] * n in Python. + ppr_scores_.assign(batch_size_, + std::vector>(num_node_types_)); + residuals_.assign(batch_size_, + std::vector>(num_node_types_)); + queue_.assign(batch_size_, std::vector>(num_node_types_)); + queued_nodes_.assign(batch_size_, + std::vector>(num_node_types_)); + + // accessor() returns a typed view into the tensor's data that + // supports [i] indexing with bounds checking in debug builds. + auto acc = seed_nodes.accessor(); + num_nodes_in_queue_ = batch_size_; + for (int32_t i = 0; i < batch_size_; ++i) { + int32_t seed = static_cast(acc[i]); + // PPR initialisation: each seed starts with residual = alpha (the + // restart probability). The first push will move alpha into ppr_score + // and distribute (1-alpha)*alpha to the seed's neighbors. + residuals_[i][seed_node_type_id][seed] = alpha_; + queue_[i][seed_node_type_id].insert(seed); + } +} + +std::optional> PPRForwardPushState::drain_queue() { + if (num_nodes_in_queue_ == 0) { + return std::nullopt; + } + + // Reset the snapshot from the previous iteration. + for (int32_t s = 0; s < batch_size_; ++s) + for (auto& qs : queued_nodes_[s]) + qs.clear(); + + // nodes_to_lookup[eid] = set of node IDs that need a neighbor fetch for + // edge type eid this round. Using a set deduplicates nodes that appear + // in multiple seeds' queues: we only fetch each (node, etype) pair once. + std::unordered_map> nodes_to_lookup; + + for (int32_t s = 0; s < batch_size_; ++s) { + for (int32_t nt = 0; nt < num_node_types_; ++nt) { + if (queue_[s][nt].empty()) + continue; + + // Move the live queue into the snapshot (no data copy — O(1)). + queued_nodes_[s][nt] = std::move(queue_[s][nt]); + queue_[s][nt].clear(); + num_nodes_in_queue_ -= static_cast(queued_nodes_[s][nt].size()); + + for (int32_t node_id : queued_nodes_[s][nt]) { + for (int32_t eid : node_type_to_edge_type_ids_[nt]) { + if (neighbor_cache_.find(pack_key(node_id, eid)) == neighbor_cache_.end()) { + nodes_to_lookup[eid].insert(node_id); + } + } + } + } + } + + std::unordered_map result; + for (auto& [eid, node_set] : nodes_to_lookup) { + std::vector ids(node_set.begin(), node_set.end()); + result[eid] = torch::tensor(ids, torch::kLong); + } + return result; +} + +void PPRForwardPushState::push_residuals( + const std::unordered_map>& + fetched_by_etype_id) { + // Step 1: Unpack the input map into a C++ map keyed by pack_key(node_id, etype_id) + // for fast lookup during the residual-push loop below. + std::unordered_map> fetched; + for (const auto& [eid, tup] : fetched_by_etype_id) { + const auto& node_ids_t = std::get<0>(tup); + const auto& flat_nbrs_t = std::get<1>(tup); + const auto& counts_t = std::get<2>(tup); + + // accessor() gives a bounds-checked, typed 1-D view into + // each tensor's data — equivalent to iterating over a NumPy array. + auto node_acc = node_ids_t.accessor(); + auto nbr_acc = flat_nbrs_t.accessor(); + auto cnt_acc = counts_t.accessor(); + + // Walk the flat neighbor list, slicing out each node's neighbors using + // the running offset into the concatenated flat buffer. + int64_t offset = 0; + for (int64_t i = 0; i < node_ids_t.size(0); ++i) { + int32_t nid = static_cast(node_acc[i]); + int64_t count = cnt_acc[i]; + std::vector nbrs(count); + for (int64_t j = 0; j < count; ++j) + nbrs[j] = static_cast(nbr_acc[offset + j]); + fetched[pack_key(nid, eid)] = std::move(nbrs); + offset += count; + } + } + + // Step 2: For every node that was in the queue (captured in queued_nodes_ + // by drain_queue()), apply one PPR push step: + // a. Absorb residual into the PPR score. + // b. Distribute (1-alpha) * residual equally to each neighbor. + // c. Enqueue any neighbor whose residual now exceeds the requeue threshold. + for (int32_t s = 0; s < batch_size_; ++s) { + for (int32_t nt = 0; nt < num_node_types_; ++nt) { + if (queued_nodes_[s][nt].empty()) + continue; + + for (int32_t src : queued_nodes_[s][nt]) { + auto& src_res = residuals_[s][nt]; + auto it = src_res.find(src); + double res = (it != src_res.end()) ? it->second : 0.0; + + // a. Absorb: move residual into the PPR score. + ppr_scores_[s][nt][src] += res; + src_res[src] = 0.0; + + int32_t total_deg = get_total_degree(src, nt); + // Destination-only nodes absorb residual but do not push further. + if (total_deg == 0) + continue; + + // b. Distribute: each neighbor receives an equal share. + double res_per_nbr = one_minus_alpha_ * res / static_cast(total_deg); + + for (int32_t eid : node_type_to_edge_type_ids_[nt]) { + // Invariant: fetched and neighbor_cache_ are mutually exclusive for + // any given (node, etype) key within one iteration. drain_queue() + // only requests a fetch for nodes absent from neighbor_cache_, so a + // key is in at most one of the two. + const std::vector* nbr_list = nullptr; + auto fi = fetched.find(pack_key(src, eid)); + if (fi != fetched.end()) { + nbr_list = &fi->second; + } else { + auto ci = neighbor_cache_.find(pack_key(src, eid)); + if (ci != neighbor_cache_.end()) + nbr_list = &ci->second; + } + if (!nbr_list || nbr_list->empty()) + continue; + + int32_t dst_nt = edge_type_to_dst_ntype_id_[eid]; + + // c. Accumulate residual for each neighbor and re-enqueue if threshold + // exceeded. + for (int32_t nbr : *nbr_list) { + residuals_[s][dst_nt][nbr] += res_per_nbr; + + double threshold = requeue_threshold_factor_ * + static_cast(get_total_degree(nbr, dst_nt)); + + if (queue_[s][dst_nt].find(nbr) == queue_[s][dst_nt].end() && + residuals_[s][dst_nt][nbr] >= threshold) { + queue_[s][dst_nt].insert(nbr); + ++num_nodes_in_queue_; + + // Promote neighbor lists to the persistent cache: this node will + // be processed next iteration, so caching avoids a re-fetch. + for (int32_t peid : node_type_to_edge_type_ids_[dst_nt]) { + uint64_t pk = pack_key(nbr, peid); + if (neighbor_cache_.find(pk) == neighbor_cache_.end()) { + auto pfi = fetched.find(pk); + if (pfi != fetched.end()) + neighbor_cache_[pk] = pfi->second; + } + } + } + } + } + } + } + } +} + +std::unordered_map> +PPRForwardPushState::extract_top_k(int32_t max_ppr_nodes) { + std::unordered_set active; + for (int32_t s = 0; s < batch_size_; ++s) + for (int32_t nt = 0; nt < num_node_types_; ++nt) + if (!ppr_scores_[s][nt].empty()) + active.insert(nt); + + std::unordered_map> result; + for (int32_t nt : active) { + std::vector flat_ids; + std::vector flat_weights; + std::vector valid_counts; + + for (int32_t s = 0; s < batch_size_; ++s) { + const auto& scores = ppr_scores_[s][nt]; + int32_t k = std::min(max_ppr_nodes, static_cast(scores.size())); + if (k > 0) { + std::vector> items(scores.begin(), scores.end()); + std::partial_sort( + items.begin(), items.begin() + k, items.end(), + [](const auto& a, const auto& b) { return a.second > b.second; }); + + for (int32_t i = 0; i < k; ++i) { + flat_ids.push_back(static_cast(items[i].first)); + // Cast to float32 for output; internal scores stay double to + // avoid accumulated rounding errors in the push loop. + flat_weights.push_back(static_cast(items[i].second)); + } + } + valid_counts.push_back(static_cast(k)); + } + + result[nt] = {torch::tensor(flat_ids, torch::kLong), + torch::tensor(flat_weights, torch::kFloat), + torch::tensor(valid_counts, torch::kLong)}; + } + return result; +} + +int32_t PPRForwardPushState::get_total_degree(int32_t node_id, int32_t ntype_id) const { + if (ntype_id >= static_cast(degree_tensors_.size())) + return 0; + const auto& t = degree_tensors_[ntype_id]; + if (t.numel() == 0) + return 0; + TORCH_CHECK(node_id < static_cast(t.size(0)), "Node ID ", node_id, + " out of range for degree tensor of ntype_id ", ntype_id, " (size=", t.size(0), + "). This indicates corrupted graph data or a sampler bug."); + // data_ptr() returns a raw C pointer to the tensor's int32 data buffer. + return t.data_ptr()[node_id]; +} diff --git a/gigl/csrc/distributed/ppr_forward_push.h b/gigl/csrc/distributed/ppr_forward_push.h new file mode 100644 index 000000000..7f0c92f49 --- /dev/null +++ b/gigl/csrc/distributed/ppr_forward_push.h @@ -0,0 +1,121 @@ +#pragma once + +#include + +#include // std::partial_sort, std::min +#include // Fixed-width integer types: int32_t, int64_t, uint32_t, uint64_t +#include // std::optional for nullable return values +#include // std::tuple for multi-value returns +#include // std::unordered_map — like Python dict, O(1) average lookup +#include // std::unordered_set — like Python set, O(1) average lookup +#include // std::vector — like Python list, contiguous in memory + +// Combine (node_id, etype_id) into a single 64-bit integer for use as a hash +// map key. A single 64-bit integer is cheaper to hash than a pair of two +// integers (std::unordered_map has no built-in pair hash). +// +// Bit layout: +// bits 63–32: node_id (upper half) +// bits 31– 0: etype_id (lower half) +// +// Both inputs are cast through uint32_t before packing. Without this, a +// negative int32_t (e.g. -1 = 0xFFFFFFFF) would be sign-extended to a full +// 64-bit value, corrupting the upper bits when shifted. Reinterpreting as +// uint32_t first treats the bit pattern as-is (no sign extension). +static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { + return (static_cast(static_cast(node_id)) << 32) | + static_cast(etype_id); +} + +// C++ kernel for the PPR Forward Push algorithm (Andersen et al., 2006). +// +// All hot-loop state (scores, residuals, queue, neighbor cache) lives inside +// this object. The distributed neighbor fetch is kept in Python because it +// involves async RPC calls that C++ cannot drive directly. +// +// Owned state: ppr_scores, residuals, queue, queued_nodes, neighbor_cache. +// Python retains ownership of: the distributed neighbor fetch (_batch_fetch_neighbors). +// +// Typical call sequence per batch: +// 1. PPRForwardPushState(seed_nodes, ...) — init per-seed residuals / queue +// while True: +// 2. drain_queue() — drain queue → nodes needing lookup +// 3. — distributed RPC fetch (stays in Python) +// 4. push_residuals(fetched_by_etype_id) — push residuals, update queue +// 5. extract_top_k(max_ppr_nodes) — top-k selection per seed per node type +class PPRForwardPushState { + public: + PPRForwardPushState(torch::Tensor seed_nodes, int32_t seed_node_type_id, double alpha, + double requeue_threshold_factor, + std::vector> node_type_to_edge_type_ids, + std::vector edge_type_to_dst_ntype_id, + std::vector degree_tensors); + + // Drain all queued nodes and return {etype_id: tensor[node_ids]} for batch + // neighbor lookup. Also snapshots the drained nodes into queued_nodes_ for + // use by push_residuals(). + // + // Return value semantics: + // - std::nullopt → queue was already empty; convergence achieved; stop the loop. + // - empty map → nodes were drained but all were cached; call push_residuals({}). + // - non-empty map → {etype_id → 1-D int64 tensor of node IDs} needing neighbor lookup. + std::optional> drain_queue(); + + // Push residuals to neighbors given the fetched neighbor data. + // + // fetched_by_etype_id: {etype_id: (node_ids_tensor, flat_nbrs_tensor, counts_tensor)} + // - node_ids_tensor: [N] int64 — source node IDs fetched for this edge type + // - flat_nbrs_tensor: [sum(counts)] int64 — all neighbor lists concatenated flat + // - counts_tensor: [N] int64 — neighbor count for each source node + void push_residuals(const std::unordered_map< + int32_t, std::tuple>& + fetched_by_etype_id); + + // Extract top-k PPR nodes per seed per node type. + // + // Returns {ntype_id: (flat_ids_tensor, flat_weights_tensor, valid_counts_tensor)}. + // Only node types that received any PPR score are included in the output. + // + // Output layout for a batch of B seeds: + // flat_ids[0 : valid_counts[0]] → top-k nodes for seed 0 + // flat_ids[valid_counts[0] : valid_counts[0]+valid_counts[1]] → top-k for seed 1 + // ... + std::unordered_map> + extract_top_k(int32_t max_ppr_nodes); + + private: + // Look up the total (across all edge types) out-degree of a node. + // Returns 0 for destination-only node types (no outgoing edges). + int32_t get_total_degree(int32_t node_id, int32_t ntype_id) const; + + // ------------------------------------------------------------------------- + // Scalar algorithm parameters + // ------------------------------------------------------------------------- + double alpha_; // Restart probability + double one_minus_alpha_; // 1 - alpha, precomputed to avoid repeated subtraction + double requeue_threshold_factor_; // alpha * eps; multiplied by degree to get per-node threshold + + int32_t batch_size_; // Number of seeds in the current batch + int32_t num_node_types_; // Total number of node types (homo + hetero) + int32_t num_nodes_in_queue_{0}; // Running count of nodes across all seeds / types + + // ------------------------------------------------------------------------- + // Graph structure (read-only after construction) + // ------------------------------------------------------------------------- + std::vector> node_type_to_edge_type_ids_; + std::vector edge_type_to_dst_ntype_id_; + std::vector degree_tensors_; + + // ------------------------------------------------------------------------- + // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]) + // ------------------------------------------------------------------------- + std::vector>> ppr_scores_; + std::vector>> residuals_; + std::vector>> queue_; + std::vector>> queued_nodes_; + + // ------------------------------------------------------------------------- + // Neighbor cache + // ------------------------------------------------------------------------- + std::unordered_map> neighbor_cache_; +}; diff --git a/gigl/distributed/cpp_extensions/ppr_forward_push.pyi b/gigl/csrc/distributed/ppr_forward_push.pyi similarity index 100% rename from gigl/distributed/cpp_extensions/ppr_forward_push.pyi rename to gigl/csrc/distributed/ppr_forward_push.pyi diff --git a/gigl/csrc/distributed/python_ppr_forward_push.cpp b/gigl/csrc/distributed/python_ppr_forward_push.cpp new file mode 100644 index 000000000..ebf3fa27a --- /dev/null +++ b/gigl/csrc/distributed/python_ppr_forward_push.cpp @@ -0,0 +1,63 @@ +// Python bindings for PPRForwardPushState. +// +// Follows PyTorch's csrc convention: pure C++ algorithm lives in +// ppr_forward_push.{h,cpp}; this file only handles type conversion between +// Python (pybind11) and C++ types, then delegates to the C++ implementation. + +#include +#include + +#include "ppr_forward_push.h" + +namespace py = pybind11; + +// drain_queue: C++ returns std::optional>. +// Exposed to Python as: None (convergence) or dict[int, Tensor]. +static py::object drain_queue_wrapper(PPRForwardPushState& self) { + auto result = self.drain_queue(); + if (!result) { + return py::none(); + } + py::dict d; + for (auto& [eid, tensor] : *result) { + d[py::int_(eid)] = tensor; + } + return d; +} + +// push_residuals: Python passes dict[int, tuple[Tensor, Tensor, Tensor]]. +// Convert to C++ map before delegating. +static void push_residuals_wrapper(PPRForwardPushState& self, py::dict fetched_by_etype_id) { + std::unordered_map> cpp_map; + for (auto item : fetched_by_etype_id) { + int32_t eid = item.first.cast(); + auto tup = item.second.cast(); + cpp_map[eid] = {tup[0].cast(), tup[1].cast(), + tup[2].cast()}; + } + self.push_residuals(cpp_map); +} + +// extract_top_k: C++ returns map>. +// Exposed to Python as dict[int, tuple[Tensor, Tensor, Tensor]]. +static py::dict extract_top_k_wrapper(PPRForwardPushState& self, int32_t max_ppr_nodes) { + auto result = self.extract_top_k(max_ppr_nodes); + py::dict d; + for (auto& [nt, tup] : result) { + d[py::int_(nt)] = + py::make_tuple(std::get<0>(tup), std::get<1>(tup), std::get<2>(tup)); + } + return d; +} + +// TORCH_EXTENSION_NAME is set by PyTorch's build system to match the Python +// module name derived from this file's path (e.g. "ppr_forward_push"). +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + py::class_(m, "PPRForwardPushState") + .def(py::init>, std::vector, + std::vector>()) + .def("drain_queue", drain_queue_wrapper) + .def("push_residuals", push_residuals_wrapper) + .def("extract_top_k", extract_top_k_wrapper); +} diff --git a/gigl/distributed/cpp_extensions/__init__.py b/gigl/distributed/cpp_extensions/__init__.py deleted file mode 100644 index d375f59b1..000000000 --- a/gigl/distributed/cpp_extensions/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -try: - from gigl.distributed.cpp_extensions.ppr_forward_push import PPRForwardPushState -except ImportError as e: - raise ImportError( - "PPR C++ extension not compiled. " - "Run `uv pip install -e .` from the GiGL root to build it." - ) from e - -__all__ = ["PPRForwardPushState"] diff --git a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp b/gigl/distributed/cpp_extensions/ppr_forward_push.cpp deleted file mode 100644 index 0af3eb2b5..000000000 --- a/gigl/distributed/cpp_extensions/ppr_forward_push.cpp +++ /dev/null @@ -1,458 +0,0 @@ -#include // Automatic conversion between C++ containers and Python types -#include // PyTorch C++ API (tensors, TORCH_CHECK) - -#include // std::partial_sort, std::min -#include // Fixed-width integer types: int32_t, int64_t, uint32_t, uint64_t -#include // std::unordered_map — like Python dict, O(1) average lookup -#include // std::unordered_set — like Python set, O(1) average lookup -#include // std::vector — like Python list, contiguous in memory - -namespace py = pybind11; // Alias for the pybind11 namespace (bridges C++ ↔ Python) - -// Combine (node_id, etype_id) into a single 64-bit integer for use as a hash -// map key. A single 64-bit integer is cheaper to hash than a pair of two -// integers (std::unordered_map has no built-in pair hash). -// -// Bit layout: -// bits 63–32: node_id (upper half) -// bits 31– 0: etype_id (lower half) -// -// Both inputs are cast through uint32_t before packing. Without this, a -// negative int32_t (e.g. -1 = 0xFFFFFFFF) would be sign-extended to a full -// 64-bit value, corrupting the upper bits when shifted. Reinterpreting as -// uint32_t first treats the bit pattern as-is (no sign extension). -// -// `static inline` means: define this function here in the translation unit -// (not in a separate object file) and ask the compiler to inline it at each -// call site instead of generating a function call. -static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { - return (static_cast(static_cast(node_id)) << 32) | - static_cast(etype_id); -} - -// C++ kernel for the PPR Forward Push algorithm (Andersen et al., 2006). -// -// All hot-loop state (scores, residuals, queue, neighbor cache) lives inside -// this object. The distributed neighbor fetch is kept in Python because it -// involves async RPC calls that C++ cannot drive directly. -// -// Owned state: ppr_scores, residuals, queue, queued_nodes, neighbor_cache. -// Python retains ownership of: the distributed neighbor fetch (_batch_fetch_neighbors). -// -// Typical call sequence per batch: -// 1. PPRForwardPushState(seed_nodes, ...) — init per-seed residuals / queue -// while True: -// 2. drain_queue() — drain queue → nodes needing lookup -// 3. — distributed RPC fetch (stays in Python) -// 4. push_residuals(fetched_by_etype_id) — push residuals, update queue -// 5. extract_top_k(max_ppr_nodes) — top-k selection per seed per node type -class PPRForwardPushState { - public: - PPRForwardPushState(torch::Tensor seed_nodes, int32_t seed_node_type_id, double alpha, - double requeue_threshold_factor, - std::vector> node_type_to_edge_type_ids, - std::vector edge_type_to_dst_ntype_id, - std::vector degree_tensors) - : alpha_(alpha), - one_minus_alpha_(1.0 - alpha), - requeue_threshold_factor_(requeue_threshold_factor), - // std::move transfers ownership of each vector into the member variable - // without copying its contents — equivalent to Python's list hand-off - // when you no longer need the original. - node_type_to_edge_type_ids_(std::move(node_type_to_edge_type_ids)), - edge_type_to_dst_ntype_id_(std::move(edge_type_to_dst_ntype_id)), - degree_tensors_(std::move(degree_tensors)) { - TORCH_CHECK(seed_nodes.dim() == 1, "seed_nodes must be 1D"); - batch_size_ = static_cast(seed_nodes.size(0)); - num_node_types_ = static_cast(node_type_to_edge_type_ids_.size()); - - // Allocate per-seed, per-node-type tables. - // .assign(n, val) fills a vector with n copies of val — like [val] * n in Python. - // Each inner element is an empty hash map / hash set for that (seed, ntype) pair. - ppr_scores_.assign(batch_size_, - std::vector>(num_node_types_)); - residuals_.assign(batch_size_, - std::vector>(num_node_types_)); - queue_.assign(batch_size_, std::vector>(num_node_types_)); - queued_nodes_.assign(batch_size_, - std::vector>(num_node_types_)); - - // accessor() returns a typed view into the tensor's data that - // supports [i] indexing with bounds checking in debug builds. Here we read - // each seed node ID from the 1-D int64 tensor. - auto acc = seed_nodes.accessor(); - num_nodes_in_queue_ = batch_size_; - for (int32_t i = 0; i < batch_size_; ++i) { - // static_cast: explicit narrowing from int64 to int32. - // The Python caller guarantees node IDs fit in 32 bits. - int32_t seed = static_cast(acc[i]); - // PPR initialisation: each seed starts with residual = alpha (the - // restart probability). The first push will move alpha into ppr_score - // and distribute (1-alpha)*alpha to the seed's neighbors. - residuals_[i][seed_node_type_id][seed] = alpha_; - queue_[i][seed_node_type_id].insert(seed); - } - } - - // Drain all queued nodes and return {etype_id: tensor[node_ids]} for batch - // neighbor lookup. Also snapshots the drained nodes into queued_nodes_ for - // use by push_residuals(). - // - // Return value semantics (py::object can hold any Python value): - // - py::none() → queue was already empty; convergence achieved; stop the loop. - // - py::dict{} → nodes were drained. The dict maps etype_id → 1-D int64 - // tensor of node IDs that need neighbor lookups this round. - // May be empty if all drained nodes were already in the cache - // or had no outgoing edges — push_residuals must still be called - // to flush their accumulated residual into ppr_scores_. - py::object drain_queue() { - if (num_nodes_in_queue_ == 0) { - return py::none(); - } - - // Reset the snapshot from the previous iteration. `auto&` is a reference - // (alias) to the existing set — clearing it modifies the original in-place - // rather than operating on a copy. - for (int32_t s = 0; s < batch_size_; ++s) - for (auto& qs : queued_nodes_[s]) - qs.clear(); - - // nodes_to_lookup[eid] = set of node IDs that need a neighbor fetch for - // edge type eid this round. Using a set deduplicates nodes that appear - // in multiple seeds' queues: we only fetch each (node, etype) pair once - // regardless of how many seeds need it. - std::unordered_map> nodes_to_lookup; - - for (int32_t s = 0; s < batch_size_; ++s) { - for (int32_t nt = 0; nt < num_node_types_; ++nt) { - if (queue_[s][nt].empty()) - continue; - - // Move the live queue into the snapshot (no data copy — O(1)). - // queue_ is then reset to an empty set so new entries added by - // push_residuals() in this same iteration don't interfere. - queued_nodes_[s][nt] = std::move(queue_[s][nt]); - queue_[s][nt].clear(); - num_nodes_in_queue_ -= static_cast(queued_nodes_[s][nt].size()); - - for (int32_t node_id : queued_nodes_[s][nt]) { - for (int32_t eid : node_type_to_edge_type_ids_[nt]) { - // Only request a fetch if the neighbor list isn't already - // cached from a previous iteration. - if (neighbor_cache_.find(pack_key(node_id, eid)) == neighbor_cache_.end()) { - nodes_to_lookup[eid].insert(node_id); - } - } - } - } - } - - // Convert to Python: {etype_id (int) → 1-D int64 tensor of node IDs}. - // py::int_(eid) wraps a C++ int as a Python int so it can be used as a - // dict key on the Python side. - py::dict result; - for (auto& [eid, node_set] : nodes_to_lookup) { - // Copy the set into a vector first: torch::tensor() requires a - // contiguous sequence, not an unordered_set iterator. - std::vector ids(node_set.begin(), node_set.end()); - result[py::int_(eid)] = torch::tensor(ids, torch::kLong); - } - return result; - } - - // Push residuals to neighbors given the fetched neighbor data. - // - // fetched_by_etype_id: {etype_id: (node_ids_tensor, flat_nbrs_tensor, counts_tensor)} - // - node_ids_tensor: [N] int64 — source node IDs fetched for this edge type - // - flat_nbrs_tensor: [sum(counts)] int64 — all neighbor lists concatenated flat - // - counts_tensor: [N] int64 — neighbor count for each source node - // - // For example, if nodes 3 and 7 were fetched for etype 0: - // node_ids = [3, 7] - // flat_nbrs = [10, 11, 12, 20] ← node 3 has nbrs {10,11,12}, node 7 has nbr {20} - // counts = [3, 1] - void push_residuals(py::dict fetched_by_etype_id) { - // Step 1: Unpack the Python dict into a C++ map for fast lookup during - // the residual-push loop below. - // fetched: pack_key(node_id, etype_id) → neighbor list (as int32_t vector) - std::unordered_map> fetched; - for (auto item : fetched_by_etype_id) { - int32_t eid = item.first.cast(); - // .cast() interprets the Python value as a tuple so we - // can index into it with [0], [1], [2]. - auto tup = item.second.cast(); - auto node_ids_t = tup[0].cast(); - auto flat_nbrs_t = tup[1].cast(); - auto counts_t = tup[2].cast(); - - // accessor() gives a bounds-checked, typed 1-D view into - // each tensor's data — equivalent to iterating over a NumPy array. - auto node_acc = node_ids_t.accessor(); - auto nbr_acc = flat_nbrs_t.accessor(); - auto cnt_acc = counts_t.accessor(); - - // Walk the flat neighbor list, slicing out each node's neighbors using - // the running offset into the concatenated flat buffer. - int64_t offset = 0; - for (int64_t i = 0; i < node_ids_t.size(0); ++i) { - int32_t nid = static_cast(node_acc[i]); - int64_t count = cnt_acc[i]; - std::vector nbrs(count); - for (int64_t j = 0; j < count; ++j) - nbrs[j] = static_cast(nbr_acc[offset + j]); - // std::move: hand off nbrs to the map without copying its contents. - fetched[pack_key(nid, eid)] = std::move(nbrs); - offset += count; - } - } - - // Step 2: For every node that was in the queue (captured in queued_nodes_ - // by drain_queue()), apply one PPR push step: - // a. Absorb residual into the PPR score. - // b. Distribute (1-alpha) * residual equally to each neighbor. - // c. Enqueue any neighbor whose residual now exceeds the requeue threshold. - for (int32_t s = 0; s < batch_size_; ++s) { - for (int32_t nt = 0; nt < num_node_types_; ++nt) { - if (queued_nodes_[s][nt].empty()) - continue; - - for (int32_t src : queued_nodes_[s][nt]) { - // `auto&` gives a reference to the residual map for this - // (seed, node_type) pair so we can read and write it without - // an extra hash lookup each time. - auto& src_res = residuals_[s][nt]; - // .find() returns an iterator; .end() means "not found". - // We treat a missing entry as residual = 0. - auto it = src_res.find(src); - double res = (it != src_res.end()) ? it->second : 0.0; - - // a. Absorb: move residual into the PPR score. - ppr_scores_[s][nt][src] += res; - src_res[src] = 0.0; - - int32_t total_deg = get_total_degree(src, nt); - // Destination-only nodes (no outgoing edges) absorb residual - // into their PPR score but do not push further. - if (total_deg == 0) - continue; - - // b. Distribute: each neighbor of src (across all edge types - // from nt) receives an equal share of the pushed residual. - double res_per_nbr = one_minus_alpha_ * res / static_cast(total_deg); - - for (int32_t eid : node_type_to_edge_type_ids_[nt]) { - // Invariant: fetched and neighbor_cache_ are mutually exclusive for - // any given (node, etype) key within one iteration. drain_queue() - // only requests a fetch for nodes absent from neighbor_cache_, so a - // key is in at most one of the two. We check fetched first since it - // is the common case for newly-seen nodes. - // - // `const std::vector*` is a pointer to a neighbor list. - // We use a pointer (rather than copying the list) so we can check - // for absence with nullptr without allocating anything. - const std::vector* nbr_list = nullptr; - auto fi = fetched.find(pack_key(src, eid)); - if (fi != fetched.end()) { - // `&fi->second` takes the address of the vector stored in - // the map — nbr_list now points to it without copying. - nbr_list = &fi->second; - } else { - auto ci = neighbor_cache_.find(pack_key(src, eid)); - if (ci != neighbor_cache_.end()) - nbr_list = &ci->second; - } - // Skip if no neighbor list is available (node has no edges of - // this type, or the fetch returned an empty list). - if (!nbr_list || nbr_list->empty()) - continue; - - int32_t dst_nt = edge_type_to_dst_ntype_id_[eid]; - - // c. For each neighbor, accumulate residual and check threshold. - // `*nbr_list` dereferences the pointer to access the vector. - for (int32_t nbr : *nbr_list) { - residuals_[s][dst_nt][nbr] += res_per_nbr; - - double threshold = requeue_threshold_factor_ * - static_cast(get_total_degree(nbr, dst_nt)); - - // Only enqueue if: (1) not already in queue for this - // iteration, and (2) residual exceeds the push threshold - // alpha * eps * degree. - if (queue_[s][dst_nt].find(nbr) == queue_[s][dst_nt].end() && - residuals_[s][dst_nt][nbr] >= threshold) { - queue_[s][dst_nt].insert(nbr); - ++num_nodes_in_queue_; // ++x is equivalent to x += 1 - - // Promote this node's neighbor lists to the persistent cache: - // it will be processed next iteration, so caching now avoids - // a re-fetch. Nodes that are never requeued (typically - // high-degree) are never promoted, keeping their large neighbor - // lists out of the cache. - for (int32_t peid : node_type_to_edge_type_ids_[dst_nt]) { - uint64_t pk = pack_key(nbr, peid); - if (neighbor_cache_.find(pk) == neighbor_cache_.end()) { - auto pfi = fetched.find(pk); - if (pfi != fetched.end()) - neighbor_cache_[pk] = pfi->second; - } - } - } - } - } - } - } - } - } - - // Extract top-k PPR nodes per seed per node type. - // - // Returns {ntype_id: (flat_ids_tensor, flat_weights_tensor, valid_counts_tensor)}. - // Only node types that received any PPR score are included in the output. - // - // Output layout for a batch of B seeds (same structure as _batch_fetch_neighbors): - // flat_ids[0 : valid_counts[0]] → top-k nodes for seed 0 - // flat_ids[valid_counts[0] : valid_counts[0]+valid_counts[1]] → top-k for seed 1 - // ... - py::dict extract_top_k(int32_t max_ppr_nodes) { - // Collect node types that have any PPR score — skip types with no activity. - std::unordered_set active; - for (int32_t s = 0; s < batch_size_; ++s) - for (int32_t nt = 0; nt < num_node_types_; ++nt) - if (!ppr_scores_[s][nt].empty()) - active.insert(nt); - - py::dict result; - for (int32_t nt : active) { - // Flat output vectors — entries for all seeds are concatenated. - std::vector flat_ids; - std::vector flat_weights; - std::vector valid_counts; - - for (int32_t s = 0; s < batch_size_; ++s) { - // `const auto&` is a read-only reference — we iterate the map - // without copying it. - const auto& scores = ppr_scores_[s][nt]; - // Cap k at the number of nodes that actually have a score. - int32_t k = std::min(max_ppr_nodes, static_cast(scores.size())); - if (k > 0) { - // Copy the map entries into a vector of (node_id, score) pairs - // so they can be sorted. std::pair is like a Python 2-tuple. - std::vector> items(scores.begin(), scores.end()); - - // std::partial_sort rearranges items so that the first k entries - // are the k largest — like Python's heapq.nlargest but in-place. - // The lambda `[](const auto& a, const auto& b) { return ...; }` - // is an anonymous comparator (like Python's `key=` argument). - // `.second` accesses the score (second element of the pair); - // `>` makes it descending (highest score first). - std::partial_sort( - items.begin(), items.begin() + k, items.end(), - [](const auto& a, const auto& b) { return a.second > b.second; }); - - for (int32_t i = 0; i < k; ++i) { - flat_ids.push_back(static_cast(items[i].first)); - // Cast to float32 for output; internal scores stay double to - // avoid accumulated rounding errors in the push loop above. - flat_weights.push_back(static_cast(items[i].second)); - } - } - valid_counts.push_back(static_cast(k)); - } - - // py::make_tuple wraps C++ values into a Python tuple. - result[py::int_(nt)] = py::make_tuple(torch::tensor(flat_ids, torch::kLong), - torch::tensor(flat_weights, torch::kFloat), - torch::tensor(valid_counts, torch::kLong)); - } - return result; - } - - private: - // Look up the total (across all edge types) out-degree of a node. - // Returns 0 for destination-only node types (no outgoing edges). - int32_t get_total_degree(int32_t node_id, int32_t ntype_id) const { - if (ntype_id >= static_cast(degree_tensors_.size())) - return 0; - const auto& t = degree_tensors_[ntype_id]; - if (t.numel() == 0) - return 0; // destination-only type: no outgoing edges - TORCH_CHECK(node_id < static_cast(t.size(0)), "Node ID ", node_id, - " out of range for degree tensor of ntype_id ", ntype_id, " (size=", t.size(0), - "). This indicates corrupted graph data or a sampler bug."); - // data_ptr() returns a raw C pointer to the tensor's int32 data - // buffer. Direct pointer indexing ([node_id]) is safe here because we - // validated the bounds with TORCH_CHECK above. - return t.data_ptr()[node_id]; - } - - // ------------------------------------------------------------------------- - // Scalar algorithm parameters - // ------------------------------------------------------------------------- - double alpha_; // Restart probability - double one_minus_alpha_; // 1 - alpha, precomputed to avoid repeated subtraction - double - requeue_threshold_factor_; // alpha * eps; multiplied by degree to get per-node threshold - - int32_t batch_size_; // Number of seeds in the current batch - int32_t num_node_types_; // Total number of node types (homo + hetero) - int32_t num_nodes_in_queue_{0}; // Running count of nodes across all seeds / types - - // ------------------------------------------------------------------------- - // Graph structure (read-only after construction) - // ------------------------------------------------------------------------- - // node_type_to_edge_type_ids_[ntype_id] → list of edge type IDs that can be - // traversed from that node type (outgoing or incoming, depending on edge_dir). - std::vector> node_type_to_edge_type_ids_; - // edge_type_to_dst_ntype_id_[eid] → node type ID at the destination end. - std::vector edge_type_to_dst_ntype_id_; - // degree_tensors_[ntype_id][node_id] → total degree of that node across all - // edge types traversable from its type. Empty tensor means no outgoing edges. - std::vector degree_tensors_; - - // ------------------------------------------------------------------------- - // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]) - // ------------------------------------------------------------------------- - // double precision avoids float32 rounding errors accumulating over 20-30 - // push iterations, which would otherwise cause ~1e-4 score errors vs the - // true PPR. Output weights are cast to float32 in extract_top_k. - // - // ppr_scores_[s][nt]: node_id → absorbed PPR score (Σ of residuals pushed so far) - std::vector>> ppr_scores_; - // residuals_[s][nt]: node_id → unabsorbed probability mass waiting to be pushed - std::vector>> residuals_; - // queue_[s][nt]: nodes whose residual exceeds the threshold and need a push next round - std::vector>> queue_; - // queued_nodes_[s][nt]: snapshot of queue_ taken by drain_queue() for the current round. - // Separating it from queue_ lets push_residuals() enqueue new nodes into queue_ without - // modifying the set currently being iterated. - std::vector>> queued_nodes_; - - // ------------------------------------------------------------------------- - // Neighbor cache - // ------------------------------------------------------------------------- - // Persistent cache: pack_key(node_id, etype_id) → neighbor list. - // Only nodes that have been re-queued (and will therefore be processed again) - // are promoted here from the per-iteration fetched map in push_residuals(). - // This avoids re-fetching neighbors for nodes processed in multiple iterations - // while keeping large neighbor lists of high-degree (never-requeued) nodes - // out of memory. - std::unordered_map> neighbor_cache_; -}; - -// Register PPRForwardPushState with Python via pybind11. -// -// TORCH_EXTENSION_NAME is set by PyTorch's setup() at build time to match the -// Python module name (e.g. "ppr_forward_push"). At import time, Python calls -// this function to populate the module with the C++ class. -PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - py::class_(m, "PPRForwardPushState") - // .def(py::init<...>()) exposes the constructor. The template arguments - // list the exact C++ parameter types so pybind11 can convert Python - // arguments to the correct C++ types automatically. - .def(py::init>, - std::vector, std::vector>()) - .def("drain_queue", &PPRForwardPushState::drain_queue) - .def("push_residuals", &PPRForwardPushState::push_residuals) - .def("extract_top_k", &PPRForwardPushState::extract_top_k); -} diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index b63329357..6285d67e6 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -14,7 +14,7 @@ from graphlearn_torch.typing import EdgeType, NodeType from graphlearn_torch.utils import merge_dict -from gigl.distributed.cpp_extensions import PPRForwardPushState +from gigl.csrc.distributed import PPRForwardPushState from gigl.distributed.dist_neighbor_sampler import DistNeighborSampler from gigl.types.graph import is_label_edge_type From c66a6e53a6e7cda2564394a2ffe61e59cc962125 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 22:21:38 +0000 Subject: [PATCH 016/148] Update --- gigl/csrc/{distributed => sampling}/__init__.py | 2 +- gigl/csrc/{distributed => sampling}/ppr_forward_push.cpp | 0 gigl/csrc/{distributed => sampling}/ppr_forward_push.h | 0 gigl/csrc/{distributed => sampling}/ppr_forward_push.pyi | 0 gigl/csrc/{distributed => sampling}/python_ppr_forward_push.cpp | 0 gigl/distributed/dist_ppr_sampler.py | 2 +- 6 files changed, 2 insertions(+), 2 deletions(-) rename gigl/csrc/{distributed => sampling}/__init__.py (74%) rename gigl/csrc/{distributed => sampling}/ppr_forward_push.cpp (100%) rename gigl/csrc/{distributed => sampling}/ppr_forward_push.h (100%) rename gigl/csrc/{distributed => sampling}/ppr_forward_push.pyi (100%) rename gigl/csrc/{distributed => sampling}/python_ppr_forward_push.cpp (100%) diff --git a/gigl/csrc/distributed/__init__.py b/gigl/csrc/sampling/__init__.py similarity index 74% rename from gigl/csrc/distributed/__init__.py rename to gigl/csrc/sampling/__init__.py index d8ffa921a..b2e23ba6c 100644 --- a/gigl/csrc/distributed/__init__.py +++ b/gigl/csrc/sampling/__init__.py @@ -1,5 +1,5 @@ try: - from gigl.csrc.distributed.ppr_forward_push import PPRForwardPushState + from gigl.csrc.sampling.ppr_forward_push import PPRForwardPushState except ImportError as e: raise ImportError( "PPR C++ extension not compiled. " diff --git a/gigl/csrc/distributed/ppr_forward_push.cpp b/gigl/csrc/sampling/ppr_forward_push.cpp similarity index 100% rename from gigl/csrc/distributed/ppr_forward_push.cpp rename to gigl/csrc/sampling/ppr_forward_push.cpp diff --git a/gigl/csrc/distributed/ppr_forward_push.h b/gigl/csrc/sampling/ppr_forward_push.h similarity index 100% rename from gigl/csrc/distributed/ppr_forward_push.h rename to gigl/csrc/sampling/ppr_forward_push.h diff --git a/gigl/csrc/distributed/ppr_forward_push.pyi b/gigl/csrc/sampling/ppr_forward_push.pyi similarity index 100% rename from gigl/csrc/distributed/ppr_forward_push.pyi rename to gigl/csrc/sampling/ppr_forward_push.pyi diff --git a/gigl/csrc/distributed/python_ppr_forward_push.cpp b/gigl/csrc/sampling/python_ppr_forward_push.cpp similarity index 100% rename from gigl/csrc/distributed/python_ppr_forward_push.cpp rename to gigl/csrc/sampling/python_ppr_forward_push.cpp diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 6285d67e6..9e8c8a482 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -14,7 +14,7 @@ from graphlearn_torch.typing import EdgeType, NodeType from graphlearn_torch.utils import merge_dict -from gigl.csrc.distributed import PPRForwardPushState +from gigl.csrc.sampling import PPRForwardPushState from gigl.distributed.dist_neighbor_sampler import DistNeighborSampler from gigl.types.graph import is_label_edge_type From 638e667f2c346286ffe64f5f2c3e55cefa14c3d0 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 25 Mar 2026 22:31:53 +0000 Subject: [PATCH 017/148] Move build_cpp_extensions.py to scripts/ and wire into relevant make targets --- Makefile | 10 +++++----- gigl/scripts/post_install.py | 2 +- .../build_cpp_extensions.py | 11 +---------- scripts/generate_compile_commands.py | 2 +- 4 files changed, 8 insertions(+), 17 deletions(-) rename build_cpp_extensions.py => scripts/build_cpp_extensions.py (73%) diff --git a/Makefile b/Makefile index 86fea095e..89416cfa7 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ assert_yaml_configs_parse: # Ex. `make unit_test_py PY_TEST_FILES="eval_metrics_test.py"` # By default, runs all tests under tests/unit. # See the help text for "--test_file_pattern" in tests/test_args.py for more details. -unit_test_py: clean_build_files_py type_check +unit_test_py: clean_build_files_py type_check build_cpp_extensions uv run python -m tests.unit.main \ --env=test \ --resource_config_uri=${GIGL_TEST_DEFAULT_RESOURCE_CONFIG} \ @@ -125,7 +125,7 @@ check_format: check_format_py check_format_scala check_format_md check_format_cp # Ex. `make integration_test PY_TEST_FILES="dataflow_test.py"` # By default, runs all tests under tests/integration. # See the help text for "--test_file_pattern" in tests/test_args.py for more details. -integration_test: +integration_test: build_cpp_extensions uv run python -m tests.integration.main \ --env=test \ --resource_config_uri=${GIGL_TEST_DEFAULT_RESOURCE_CONFIG} \ @@ -162,7 +162,7 @@ type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs build_cpp_extensions: - uv run --no-sync python build_cpp_extensions.py build_ext --inplace + uv run --no-sync python scripts/build_cpp_extensions.py build_ext --inplace lint_cpp: uv run python scripts/generate_compile_commands.py @@ -282,7 +282,7 @@ run_all_e2e_tests: # Example: # `make compiled_pipeline_path="/tmp/gigl/my_pipeline.yaml" compile_gigl_kubeflow_pipeline` # Can be a GCS URI as well -compile_gigl_kubeflow_pipeline: compile_jars push_new_docker_images +compile_gigl_kubeflow_pipeline: build_cpp_extensions compile_jars push_new_docker_images uv run python -m gigl.orchestration.kubeflow.runner \ --action=compile \ --container_image_cuda=${DOCKER_IMAGE_MAIN_CUDA_NAME_WITH_TAG} \ @@ -308,7 +308,7 @@ _skip_build_deps: # job_name=... \ , and other params # compiled_pipeline_path="/tmp/gigl/my_pipeline.yaml" \ # run_dev_gnn_kubeflow_pipeline -run_dev_gnn_kubeflow_pipeline: $(if $(compiled_pipeline_path), _skip_build_deps, compile_jars push_new_docker_images) +run_dev_gnn_kubeflow_pipeline: $(if $(compiled_pipeline_path), _skip_build_deps, build_cpp_extensions compile_jars push_new_docker_images) uv run python -m gigl.orchestration.kubeflow.runner \ $(if $(compiled_pipeline_path),,--container_image_cuda=${DOCKER_IMAGE_MAIN_CUDA_NAME_WITH_TAG}) \ $(if $(compiled_pipeline_path),,--container_image_cpu=${DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG}) \ diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index 677e45a6c..eed1528f6 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -63,7 +63,7 @@ def main(): try: print("Building C++ extensions...") subprocess.run( - [sys.executable, "build_cpp_extensions.py", "build_ext", "--inplace"], + [sys.executable, "scripts/build_cpp_extensions.py", "build_ext", "--inplace"], cwd=repo_root, check=True, ) diff --git a/build_cpp_extensions.py b/scripts/build_cpp_extensions.py similarity index 73% rename from build_cpp_extensions.py rename to scripts/build_cpp_extensions.py index a0095464a..d05740860 100644 --- a/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -20,16 +20,7 @@ def find_cpp_extensions() -> list[CppExtension]: """Auto-discover pybind11 extension modules under ``gigl/csrc/``. Following PyTorch's csrc convention, only files named ``python_*.cpp`` are - compiled as Python extension modules. Pure C++ files (without the - ``python_`` prefix) are used only in C++ unit tests. - - The module name is derived from the file path with the ``python_`` prefix - stripped, so ``gigl/csrc/distributed/python_ppr_forward_push.cpp`` is - importable as ``gigl.csrc.distributed.ppr_forward_push``. - - If a matching implementation file exists alongside the binding file (e.g. - ``ppr_forward_push.cpp`` next to ``python_ppr_forward_push.cpp``), it is - compiled into the same extension module. + compiled as Python extension modules. Returns an empty list if ``gigl/csrc/`` does not yet exist. """ diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 767a4860b..eec176848 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -26,7 +26,7 @@ def main() -> None: # Always rebuild C++ extensions before generating compile_commands.json so # the database reflects the current state of the code. subprocess.run( - [sys.executable, "build_cpp_extensions.py", "build_ext", "--inplace"], + [sys.executable, "scripts/build_cpp_extensions.py", "build_ext", "--inplace"], cwd=repo_root, check=True, ) From 416f6b4dd01079667d82660eac072eab0b247f30 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 30 Mar 2026 22:33:43 +0000 Subject: [PATCH 018/148] Initial commit --- gigl/distributed/dist_dataset.py | 24 +-- gigl/distributed/dist_ppr_sampler.py | 74 +++------ gigl/distributed/dist_sampling_producer.py | 8 +- gigl/distributed/sampler_options.py | 6 +- gigl/distributed/utils/degree.py | 147 +++++++++++++----- .../graph_transformer/graph_transformer.py | 3 + tests/unit/distributed/utils/degree_test.py | 58 ++++--- 7 files changed, 198 insertions(+), 122 deletions(-) diff --git a/gigl/distributed/dist_dataset.py b/gigl/distributed/dist_dataset.py index f495a6d96..20436f4bc 100644 --- a/gigl/distributed/dist_dataset.py +++ b/gigl/distributed/dist_dataset.py @@ -78,7 +78,7 @@ def __init__( Union[FeatureInfo, dict[EdgeType, FeatureInfo]] ] = None, degree_tensor: Optional[ - Union[torch.Tensor, dict[EdgeType, torch.Tensor]] + Union[torch.Tensor, dict[NodeType, torch.Tensor]] ] = None, ) -> None: """ @@ -104,7 +104,7 @@ def __init__( Note this will be None in the homogeneous case if the data has no node features, or will only contain node types with node features in the heterogeneous case. edge_feature_info: Optional[Union[FeatureInfo, dict[EdgeType, FeatureInfo]]]: Dimension of edge features and its data type, will be a dict if heterogeneous. Note this will be None in the homogeneous case if the data has no edge features, or will only contain edge types with edge features in the heterogeneous case. - degree_tensor: Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]]: Pre-computed degree tensor. Lazily computed on first access via the degree_tensor property. + degree_tensor: Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]]: Pre-computed degree tensor. Lazily computed on first access via the degree_tensor property. """ self._rank: int = rank self._world_size: int = world_size @@ -141,7 +141,7 @@ def __init__( self._edge_feature_info = edge_feature_info self._degree_tensor: Optional[ - Union[torch.Tensor, dict[EdgeType, torch.Tensor]] + Union[torch.Tensor, dict[NodeType, torch.Tensor]] ] = degree_tensor # TODO (mkolodner-sc): Modify so that we don't need to rely on GLT's base variable naming (i.e. partition_idx, num_partitions) in favor of more clear @@ -300,7 +300,7 @@ def edge_feature_info( @property def degree_tensor( self, - ) -> Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: + ) -> Union[torch.Tensor, dict[NodeType, torch.Tensor]]: """ Lazily compute and return the degree tensor for the graph. @@ -308,15 +308,19 @@ def degree_tensor( all-reduce to aggregate across all machines. Requires torch.distributed to be initialized. + For heterogeneous graphs, degrees are summed across all edge types sharing + the same anchor node type (determined by ``self._edge_dir``), yielding one + ``int16`` tensor per node type rather than one per edge type. + Over-counting correction (for processes sharing the same data on the same machine) is handled automatically by detecting the distributed topology. The result is cached for subsequent accesses. Returns: - Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: The aggregated degree tensor. + Union[torch.Tensor, dict[NodeType, torch.Tensor]]: The aggregated degree tensor. - For homogeneous graphs: A tensor of shape [num_nodes]. - - For heterogeneous graphs: A dict mapping EdgeType to degree tensors. + - For heterogeneous graphs: A dict mapping NodeType to ``int16`` degree tensors. Raises: RuntimeError: If torch.distributed is not initialized. @@ -326,7 +330,9 @@ def degree_tensor( if self.graph is None: raise ValueError("Dataset graph is None. Cannot compute degrees.") - self._degree_tensor = compute_and_broadcast_degree_tensor(self.graph) + self._degree_tensor = compute_and_broadcast_degree_tensor( + self.graph, edge_dir=self._edge_dir + ) return self._degree_tensor @property @@ -857,7 +863,7 @@ def share_ipc( Optional[Union[int, dict[NodeType, int]]], Optional[Union[FeatureInfo, dict[NodeType, FeatureInfo]]], Optional[Union[FeatureInfo, dict[EdgeType, FeatureInfo]]], - Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]], + Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]], ]: """ Serializes the member variables of the DistDatasetClass @@ -879,7 +885,7 @@ def share_ipc( Optional[Union[int, dict[NodeType, int]]]: Number of test nodes on the current machine. Will be a dict if heterogeneous. Optional[Union[FeatureInfo, dict[NodeType, FeatureInfo]]]: Node feature dim and its data type, will be a dict if heterogeneous Optional[Union[FeatureInfo, dict[EdgeType, FeatureInfo]]]: Edge feature dim and its data type, will be a dict if heterogeneous - Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]]: Degree tensors, will be a dict if heterogeneous + Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]]: Degree tensors, will be a dict if heterogeneous """ # TODO (mkolodner-sc): Investigate moving share_memory calls to the build() function diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 17673a72d..34cb1661b 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -103,7 +103,7 @@ def __init__( max_ppr_nodes: int = 50, num_neighbors_per_hop: int = 100_000, total_degree_dtype: torch.dtype = torch.int32, - degree_tensors: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], + degree_tensors: Union[torch.Tensor, dict[NodeType, torch.Tensor]], **kwargs, ): super().__init__(*args, **kwargs) @@ -144,69 +144,45 @@ def __init__( ] self._is_homogeneous = True - # Precompute total degree per node type: the sum of degrees across all - # edge types traversable from that node type. This is a graph-level - # property used on every PPR iteration, so computing it once at init - # avoids per-node summation and cache lookups in the hot loop. - # TODO (mkolodner-sc): This trades memory for throughput — we - # materialize a tensor per node type to avoid recomputing total degree - # on every neighbor during sampling. Computing it here (rather than in - # the dataset) also keeps the door open for edge-specific degree - # strategies. If memory becomes a bottleneck, revisit this. + # The dataset pre-aggregates degrees per node type as int16. + # _build_total_degree_tensors reindexes by node type with no further casting. self._node_type_to_total_degree: dict[ NodeType, torch.Tensor - ] = self._build_total_degree_tensors(degree_tensors, total_degree_dtype) + ] = self._build_total_degree_tensors(degree_tensors) def _build_total_degree_tensors( self, - degree_tensors: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], - dtype: torch.dtype, + degree_tensors: Union[torch.Tensor, dict[NodeType, torch.Tensor]], ) -> dict[NodeType, torch.Tensor]: - """Build total-degree tensors by summing per-edge-type degrees for each node type. + """Reindex pre-aggregated per-node-type degree tensors for use in the PPR loop. - For homogeneous graphs, the total degree is just the single degree tensor. - For heterogeneous graphs, it sums degree tensors across all edge types - traversable from each node type, padding shorter tensors with zeros. + The dataset provides degrees already summed across edge types per node type + (as ``int16``). This method maps those tensors into the internal node-type + keying used by the sampler, with no further summation or dtype casting. Args: - degree_tensors: Per-edge-type degree tensors from the dataset. - dtype: Dtype for the output tensors. + degree_tensors: Per-node-type degree tensors from the dataset, already + aggregated across edge types. Returns: - Dict mapping node type to a 1-D tensor of total degrees. - """ - result: dict[NodeType, torch.Tensor] = {} + Dict mapping node type to a 1-D degree tensor. + Raises: + ValueError: If a required node type is absent from ``degree_tensors``. + """ if self._is_homogeneous: assert isinstance(degree_tensors, torch.Tensor) - # Single edge type: degree values fit directly in the target dtype. - result[_PPR_HOMOGENEOUS_NODE_TYPE] = degree_tensors.to(dtype) - else: - assert isinstance(degree_tensors, dict) - dtype_max = torch.iinfo(dtype).max - for node_type, edge_types in self._node_type_to_edge_types.items(): - max_len = 0 - for et in edge_types: - if et not in degree_tensors: - raise ValueError( - f"Edge type {et} not found in degree tensors. " - f"Available: {list(degree_tensors.keys())}" - ) - max_len = max(max_len, len(degree_tensors[et])) - - # Each degree tensor is indexed by node ID (derived from CSR - # indptr), so index i in every edge type's tensor refers to - # the same node. Element-wise summation gives the total degree - # per node across all edge types. Shorter tensors are padded - # implicitly (only the first len(et_degrees) entries are added). - # Sum in int64: aggregate degrees are bounded by partition size - # and fit comfortably within int64 range in practice. - summed = torch.zeros(max_len, dtype=torch.int64) - for et in edge_types: - et_degrees = degree_tensors[et] - summed[: len(et_degrees)] += et_degrees.to(torch.int64) - result[node_type] = summed.clamp(max=dtype_max).to(dtype) + return {_PPR_HOMOGENEOUS_NODE_TYPE: degree_tensors} + assert isinstance(degree_tensors, dict) + result: dict[NodeType, torch.Tensor] = {} + for node_type in self._node_type_to_edge_types: + if node_type not in degree_tensors: + raise ValueError( + f"Node type '{node_type}' not found in degree tensors. " + f"Available: {list(degree_tensors.keys())}" + ) + result[node_type] = degree_tensors[node_type] return result def _get_total_degree(self, node_id: int, node_type: NodeType) -> int: diff --git a/gigl/distributed/dist_sampling_producer.py b/gigl/distributed/dist_sampling_producer.py index e9c8cc0b8..3f630183e 100644 --- a/gigl/distributed/dist_sampling_producer.py +++ b/gigl/distributed/dist_sampling_producer.py @@ -29,7 +29,7 @@ SamplingConfig, SamplingType, ) -from graphlearn_torch.typing import EdgeType +from graphlearn_torch.typing import EdgeType, NodeType from graphlearn_torch.utils import seed_everything from torch._C import _set_worker_signal_handlers from torch.utils.data.dataloader import DataLoader @@ -60,7 +60,7 @@ def _sampling_worker_loop( sampling_completed_worker_count, # mp.Value mp_barrier: Barrier, sampler_options: SamplerOptions, - degree_tensors: Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]], + degree_tensors: Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]], ): dist_sampler = None try: @@ -224,14 +224,14 @@ def init(self): # where torch.distributed IS initialized — lets the tensor be shared # to workers via IPC. degree_tensors: Optional[ - Union[torch.Tensor, dict[EdgeType, torch.Tensor]] + Union[torch.Tensor, dict[NodeType, torch.Tensor]] ] = None if isinstance(self._sampler_options, PPRSamplerOptions): assert isinstance(self.data, GiglDistDataset) degree_tensors = self.data.degree_tensor if isinstance(degree_tensors, dict): logger.info( - f"Pre-computed degree tensors for PPR sampling across {len(degree_tensors)} edge types." + f"Pre-computed degree tensors for PPR sampling across {len(degree_tensors)} node types." ) else: logger.info( diff --git a/gigl/distributed/sampler_options.py b/gigl/distributed/sampler_options.py index d87a83d52..b3165b2af 100644 --- a/gigl/distributed/sampler_options.py +++ b/gigl/distributed/sampler_options.py @@ -56,9 +56,9 @@ class PPRSamplerOptions: num_neighbors_per_hop: Maximum number of neighbors fetched per node per edge type during PPR traversal. Set large to approximate fetching all neighbors. - total_degree_dtype: Dtype for precomputed total-degree tensors. Defaults - to ``torch.int32``, which supports total degrees up to ~2 billion. - Use a larger dtype if nodes have exceptionally high aggregate degrees. + total_degree_dtype: Retained for backwards compatibility; currently unused. + Degree tensors are stored as ``int16`` and no dtype conversion is + applied in the sampler. """ alpha: float = 0.5 diff --git a/gigl/distributed/utils/degree.py b/gigl/distributed/utils/degree.py index 0785a68a7..188dfa4de 100644 --- a/gigl/distributed/utils/degree.py +++ b/gigl/distributed/utils/degree.py @@ -27,38 +27,46 @@ import torch from graphlearn_torch.data import Graph -from torch_geometric.typing import EdgeType +from torch_geometric.typing import EdgeType, NodeType from gigl.common.logger import Logger from gigl.distributed.utils.device import get_device_from_process_group from gigl.distributed.utils.networking import get_internal_ip_from_all_ranks +from gigl.types.graph import is_label_edge_type logger = Logger() def compute_and_broadcast_degree_tensor( graph: Union[Graph, dict[EdgeType, Graph]], -) -> Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: + edge_dir: str, +) -> Union[torch.Tensor, dict[NodeType, torch.Tensor]]: """ Compute node degrees from a graph and aggregate across all machines. - Computes degrees from the CSR row pointers (indptr) and performs all-reduce - to aggregate across ranks. + For heterogeneous graphs, degrees are summed across all edge types sharing + the same anchor node type (source for ``edge_dir="out"``, destination for + ``edge_dir="in"``), then all-reduced across ranks. The result is one + ``int16`` tensor per anchor node type rather than one per edge type, + reducing both stored memory and the number of all-reduce calls. Over-counting correction (for processes sharing the same data) is handled automatically by detecting the distributed topology. Args: graph: A Graph (homogeneous) or dict[EdgeType, Graph] (heterogeneous). + edge_dir: ``"out"`` to group by source node type (out-degree); + ``"in"`` to group by destination node type (in-degree). Returns: - Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: The aggregated degree tensors. + Union[torch.Tensor, dict[NodeType, torch.Tensor]]: The aggregated degree tensors. - For homogeneous graphs: A tensor of shape [num_nodes]. - - For heterogeneous graphs: A dict mapping EdgeType to degree tensors. + - For heterogeneous graphs: A dict mapping NodeType to ``int16`` degree tensors, + where each entry is the total degree across all edge types for that anchor node type. Raises: RuntimeError: If torch.distributed is not initialized. - ValueError: If topology is unavailable. + ValueError: If topology is unavailable for a homogeneous graph. """ if not torch.distributed.is_initialized(): raise RuntimeError( @@ -71,20 +79,10 @@ def compute_and_broadcast_degree_tensor( if topo is None or topo.indptr is None: raise ValueError("Topology/indptr not available for graph.") local_degrees: Union[ - torch.Tensor, dict[EdgeType, torch.Tensor] + torch.Tensor, dict[NodeType, torch.Tensor] ] = _compute_degrees_from_indptr(topo.indptr) else: - local_dict: dict[EdgeType, torch.Tensor] = {} - for edge_type, edge_graph in graph.items(): - topo = edge_graph.topo - if topo is None or topo.indptr is None: - logger.warning( - f"Topology/indptr not available for edge type {edge_type}, using empty tensor." - ) - local_dict[edge_type] = torch.empty(0, dtype=torch.int16) - else: - local_dict[edge_type] = _compute_degrees_from_indptr(topo.indptr) - local_degrees = local_dict + local_degrees = _compute_hetero_degrees_by_node_type(graph, edge_dir) # All-reduce across ranks (over-counting correction handled internally) result = _all_reduce_degrees(local_degrees) @@ -98,19 +96,90 @@ def compute_and_broadcast_degree_tensor( else: logger.info("Graph contained 0 nodes when computing degrees") else: - for edge_type, degrees in result.items(): + for node_type, degrees in result.items(): if degrees.numel() > 0: logger.info( - f"{edge_type}: {degrees.size(0)} nodes, max={degrees.max().item()}, min={degrees.min().item()}" + f"{node_type}: {degrees.size(0)} nodes, max={degrees.max().item()}, min={degrees.min().item()}" ) else: logger.info( - f"Graph contained 0 nodes for edge type {edge_type} when computing degrees" + f"Graph contained 0 nodes for node type {node_type} when computing degrees" ) return result +def _compute_hetero_degrees_by_node_type( + graph: dict[EdgeType, Graph], + edge_dir: str, +) -> dict[NodeType, torch.Tensor]: + """Sum per-edge-type degrees into per-anchor-node-type totals. + + Label edge types (ABLP supervision edges) are excluded — they should not + contribute to degree counts used in PPR, matching the sampler's own exclusion. + + Uses a two-pass approach to avoid dynamic accumulator resizing: + + - Pass 1: compute ``int32`` degrees per edge type and record the maximum + node count per anchor type (to pre-size the accumulator). + - Pass 2: allocate one ``int32`` accumulator per anchor type and sum. + + Returns ``int32`` tensors; the caller is responsible for clamping to + ``int16`` after the all-reduce (see ``_all_reduce_degrees``). + + All anchor node types derived from non-label ``graph.keys()`` are present in + the output (with size-0 tensors for types whose ``indptr`` is unavailable), + ensuring symmetric participation in the subsequent all-reduce. + + Args: + graph: Heterogeneous graph mapping EdgeType to Graph. + edge_dir: ``"out"`` to anchor on source node type; ``"in"`` to anchor + on destination node type. + + Returns: + dict[NodeType, torch.Tensor]: ``int32`` total-degree tensor per anchor node type. + """ + # All anchor node types must appear in the output so the all_reduce is + # symmetric across ranks, even if this rank has no edges for a given type. + # Label edge types are excluded — they represent ABLP supervision edges, not + # structural neighbors, and should not contribute to degree counts used in PPR. + anchor_ntypes: set[NodeType] = { + etype[-1] if edge_dir == "in" else etype[0] + for etype in graph.keys() + if not is_label_edge_type(etype) + } + + # Pass 1: compute int32 degrees per valid edge type and track max node + # count per anchor type. int32 is sufficient: per-node degrees are always + # well below int32 max for any realistic graph. + et_degrees_i32: dict[EdgeType, torch.Tensor] = {} + max_sizes: dict[NodeType, int] = {ntype: 0 for ntype in anchor_ntypes} + for edge_type, edge_graph in graph.items(): + if is_label_edge_type(edge_type): + continue + anchor_ntype: NodeType = edge_type[-1] if edge_dir == "in" else edge_type[0] + topo = edge_graph.topo + if topo is None or topo.indptr is None: + logger.warning( + f"Topology/indptr not available for edge type {edge_type}, skipping." + ) + continue + degrees_i32 = (topo.indptr[1:] - topo.indptr[:-1]).to(torch.int32) + et_degrees_i32[edge_type] = degrees_i32 + max_sizes[anchor_ntype] = max(max_sizes[anchor_ntype], len(degrees_i32)) + + # Pass 2: allocate accumulators once (sized from pass 1) and sum. + accumulators: dict[NodeType, torch.Tensor] = { + ntype: torch.zeros(size, dtype=torch.int32) + for ntype, size in max_sizes.items() + } + for edge_type, degrees_i32 in et_degrees_i32.items(): + anchor_ntype = edge_type[-1] if edge_dir == "in" else edge_type[0] + accumulators[anchor_ntype][: len(degrees_i32)] += degrees_i32 + + return accumulators + + def _pad_to_size(tensor: torch.Tensor, target_size: int) -> torch.Tensor: """Pad tensor with zeros to reach target_size.""" if tensor.size(0) >= target_size: @@ -135,12 +204,12 @@ def _compute_degrees_from_indptr(indptr: torch.Tensor) -> torch.Tensor: def _all_reduce_degrees( - local_degrees: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], -) -> Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: + local_degrees: Union[torch.Tensor, dict[NodeType, torch.Tensor]], +) -> Union[torch.Tensor, dict[NodeType, torch.Tensor]]: """All-reduce degree tensors across ranks, handling both homogeneous and heterogeneous cases. - For heterogeneous graphs, iterates over the edge types in local_degrees. All partitions - are expected to have entries for all edge types (even if some have empty tensors). + For heterogeneous graphs, iterates over the node types in local_degrees. All partitions + are expected to have entries for all node types (even if some have empty tensors). Moves tensors to GPU for the all-reduce if using NCCL backend (which requires CUDA), otherwise keeps tensors on CPU (for Gloo backend). @@ -164,12 +233,12 @@ def _all_reduce_degrees( IP addresses, then divides by that count to correct the over-counting. Args: - local_degrees: Either a single tensor (homogeneous) or dict mapping EdgeType + local_degrees: Either a single tensor (homogeneous) or dict mapping NodeType to tensors (heterogeneous). For heterogeneous graphs, all partitions must - have entries for all edge types. + have entries for all node types. Returns: - Aggregated degree tensors in the same format as input. + Aggregated degree tensors in the same format as input, stored as ``int16``. Raises: RuntimeError: If torch.distributed is not initialized. @@ -195,22 +264,24 @@ def reduce_tensor(tensor: torch.Tensor) -> torch.Tensor: torch.distributed.all_reduce(local_size, op=torch.distributed.ReduceOp.MAX) max_size = int(local_size.item()) - # Pad, convert to int64 (all_reduce doesn't support int16), move to device - padded = _pad_to_size(tensor, max_size).to(torch.int64).to(device) + # Pad and convert to int32 for the all-reduce (int16 is not supported). + # int32 is sufficient: the raw sum across W ranks is at most W * max_degree, + # which fits comfortably in int32 for any realistic world size and degree. + padded = _pad_to_size(tensor, max_size).to(torch.int32).to(device) torch.distributed.all_reduce(padded, op=torch.distributed.ReduceOp.SUM) - # Correct for over-counting, move back to CPU, and clamp to int16 - # TODO (mkolodner-sc): Potentially want to paramaterize this in the future if we want degrees higher than the int16 max. + # Correct for over-counting, move back to CPU, and clamp to int16. + # TODO (mkolodner-sc): Potentially want to parameterize this in the future if we want degrees higher than the int16 max. return _clamp_to_int16((padded // local_world_size).cpu()) # Homogeneous case if isinstance(local_degrees, torch.Tensor): return reduce_tensor(local_degrees) - # Heterogeneous case: all-reduce each edge type - # Sort edge types for deterministic ordering across ranks - result: dict[EdgeType, torch.Tensor] = {} - for edge_type in sorted(local_degrees.keys()): - result[edge_type] = reduce_tensor(local_degrees[edge_type]) + # Heterogeneous case: all-reduce each node type. + # Sort node types for deterministic ordering across ranks. + result: dict[NodeType, torch.Tensor] = {} + for node_type in sorted(local_degrees.keys()): + result[node_type] = reduce_tensor(local_degrees[node_type]) return result diff --git a/gigl/src/common/models/graph_transformer/graph_transformer.py b/gigl/src/common/models/graph_transformer/graph_transformer.py index 4308b495f..d8e1a7370 100644 --- a/gigl/src/common/models/graph_transformer/graph_transformer.py +++ b/gigl/src/common/models/graph_transformer/graph_transformer.py @@ -547,6 +547,9 @@ def __init__( self._feature_embedding_layer_dict = feature_embedding_layer_dict self._pe_integration_mode = pe_integration_mode self._num_heads = num_heads + # Explicit annotation so mypy can narrow past the None check below; + # register_buffer sets the value at runtime. + self._sequence_positional_encoding_table: Optional[torch.Tensor] if self._sequence_positional_encoding_type == "sinusoidal": self.register_buffer( "_sequence_positional_encoding_table", diff --git a/tests/unit/distributed/utils/degree_test.py b/tests/unit/distributed/utils/degree_test.py index 6836e4581..16f334509 100644 --- a/tests/unit/distributed/utils/degree_test.py +++ b/tests/unit/distributed/utils/degree_test.py @@ -60,7 +60,7 @@ def test_homogeneous_graph(self): dataset = create_homogeneous_dataset(edge_index=edge_index) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph) + result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") assert isinstance(result, torch.Tensor) expected = _compute_expected_degrees_from_edge_index(edge_index, num_nodes) @@ -68,20 +68,28 @@ def test_homogeneous_graph(self): self.assert_tensor_equality(result, expected) def test_heterogeneous_graph(self): - """Test degree computation for a heterogeneous graph.""" + """Test degree computation for a heterogeneous graph. + + Result is keyed by anchor node type (source for edge_dir="out"), not edge type. + Degrees are summed across all edge types sharing the same anchor node type. + """ edge_indices = DEFAULT_HETEROGENEOUS_EDGE_INDICES dataset = create_heterogeneous_dataset(edge_indices=edge_indices) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph) + result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") assert isinstance(result, dict) - self.assertEqual(set(result.keys()), set(edge_indices.keys())) + expected_node_types = {etype[0] for etype in edge_indices.keys()} + self.assertEqual(set(result.keys()), expected_node_types) + # For the default test data each source node type maps to exactly one edge type, + # so per-node-type degrees equal per-edge-type degrees. for edge_type, edge_index in edge_indices.items(): + src_node_type = edge_type[0] num_nodes = int(edge_index[0].max().item() + 1) expected = _compute_expected_degrees_from_edge_index(edge_index, num_nodes) - self.assert_tensor_equality(result[edge_type], expected) + self.assert_tensor_equality(result[src_node_type], expected) def test_heterogeneous_graph_with_missing_topology(self): """Test that edge types with missing topology get empty tensors. @@ -113,16 +121,18 @@ def test_heterogeneous_graph_with_missing_topology(self): # Manually set one graph's topology to None to test the edge case dataset.graph[edge_type_without_topo].topo = None - result = compute_and_broadcast_degree_tensor(dataset.graph) + result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") assert isinstance(result, dict) - self.assertEqual(set(result.keys()), set(edge_types)) + # Keys are source node types (anchor for edge_dir="out"), not edge types. + expected_node_types = {etype[0] for etype in edge_types} + self.assertEqual(set(result.keys()), expected_node_types) - # Edge type with topology should have computed degrees - self.assert_tensor_equality(result[edge_type_with_topo], expected_degrees) + # Edge type with topology: anchor node type should have computed degrees. + self.assert_tensor_equality(result[edge_type_with_topo[0]], expected_degrees) - # Edge type without topology should have empty tensor - self.assertEqual(result[edge_type_without_topo].numel(), 0) + # Edge type without topology: anchor node type should have empty tensor. + self.assertEqual(result[edge_type_without_topo[0]].numel(), 0) def _run_local_world_size_correction_homogeneous( @@ -142,7 +152,7 @@ def _run_local_world_size_correction_homogeneous( try: dataset = create_homogeneous_dataset(edge_index=edge_index) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph) + result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") assert isinstance(result, torch.Tensor) assert_tensor_equality(result, expected_degrees) @@ -157,7 +167,10 @@ def _run_local_world_size_correction_heterogeneous( edge_indices: dict, expected_degrees: dict, ) -> None: - """Worker function for multi-process local_world_size correction test (heterogeneous).""" + """Worker function for multi-process local_world_size correction test (heterogeneous). + + expected_degrees must be keyed by node type (anchor for edge_dir="out"). + """ dist.init_process_group( backend="gloo", init_method=init_method, @@ -167,12 +180,12 @@ def _run_local_world_size_correction_heterogeneous( try: dataset = create_heterogeneous_dataset(edge_indices=edge_indices) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph) + result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") assert isinstance(result, dict) assert set(result.keys()) == set(expected_degrees.keys()) - for edge_type, expected in expected_degrees.items(): - assert_tensor_equality(result[edge_type], expected) + for node_type, expected in expected_degrees.items(): + assert_tensor_equality(result[node_type], expected) finally: dist.destroy_process_group() @@ -204,13 +217,16 @@ def test_local_world_size_correction_heterogeneous(self): """Test over-counting correction for heterogeneous graphs with 2 processes.""" edge_indices = DEFAULT_HETEROGENEOUS_EDGE_INDICES + # Build expected degrees keyed by source node type (anchor for edge_dir="out"). + # For the default test data each source node type maps to exactly one edge type. expected_degrees = {} for edge_type, edge_index in edge_indices.items(): + src_node_type = edge_type[0] num_nodes = int(edge_index[0].max().item() + 1) raw_degrees = _compute_expected_degrees_from_edge_index( edge_index, num_nodes ) - expected_degrees[edge_type] = raw_degrees + expected_degrees[src_node_type] = raw_degrees init_method = get_process_group_init_method() mp.spawn( @@ -263,12 +279,16 @@ def test_degree_tensor_heterogeneous(self): result = dataset.degree_tensor assert isinstance(result, dict) - self.assertEqual(set(result.keys()), set(edge_indices.keys())) + # degree_tensor is keyed by node type (anchor for dataset's edge_dir="out"), not edge type. + expected_node_types = {etype[0] for etype in edge_indices.keys()} + self.assertEqual(set(result.keys()), expected_node_types) + # For the default test data each source node type maps to exactly one edge type. for edge_type, edge_index in edge_indices.items(): + src_node_type = edge_type[0] num_nodes = int(edge_index[0].max().item() + 1) expected = _compute_expected_degrees_from_edge_index(edge_index, num_nodes) - self.assert_tensor_equality(result[edge_type], expected) + self.assert_tensor_equality(result[src_node_type], expected) class TestHelperFunctions(TestCase): From 91d99d3a6ce6e4c4e0cfadf4e796356cec3ed101 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 31 Mar 2026 16:59:07 +0000 Subject: [PATCH 019/148] Update --- gigl/distributed/base_dist_loader.py | 7 +++++++ gigl/distributed/dist_sampling_producer.py | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/gigl/distributed/base_dist_loader.py b/gigl/distributed/base_dist_loader.py index ed0783ef6..4823813f1 100644 --- a/gigl/distributed/base_dist_loader.py +++ b/gigl/distributed/base_dist_loader.py @@ -566,6 +566,13 @@ def _init_colocated_connections( self._channel = producer.output_channel self._mp_producer = producer + # Run distributed collectives (e.g. degree tensor all_reduce for PPR) + # BEFORE the staggered sleep. Collectives require all ranks to + # participate simultaneously; sleeping first would cause all ranks to + # exit the collective together and then proceed to worker spawning at + # the same time, nullifying the stagger. + producer.pre_init_collectives() + # Staggered init — sleep proportional to local_rank to avoid # concurrent initialization spikes that cause CPU memory OOM. logger.info( diff --git a/gigl/distributed/dist_sampling_producer.py b/gigl/distributed/dist_sampling_producer.py index 3f630183e..1294d2d4d 100644 --- a/gigl/distributed/dist_sampling_producer.py +++ b/gigl/distributed/dist_sampling_producer.py @@ -216,6 +216,24 @@ def __init__( super().__init__(data, sampler_input, sampling_config, worker_options, channel) self._sampler_options = sampler_options + def pre_init_collectives(self) -> None: + """Run distributed collectives that must complete before the staggered init sleep. + + ``init()`` calls ``self.data.degree_tensor``, which triggers a + ``torch.distributed.all_reduce``. Collectives require all ranks to + participate simultaneously. If that collective runs inside ``init()`` + (after the staggered sleep), every rank exits the collective at the same + instant and proceeds to worker spawning together, negating the stagger. + + Call this before the staggered sleep so all ranks complete the collective + together, then the sleep staggering applies only to the expensive worker- + spawn step. The result is cached on the dataset; ``init()`` reuses it + without re-running the collective. + """ + if isinstance(self._sampler_options, PPRSamplerOptions): + assert isinstance(self.data, GiglDistDataset) + _ = self.data.degree_tensor + def init(self): r"""Create the subprocess pool. Init samplers and rpc server.""" # Extract degree tensors before spawning workers. Worker subprocesses From 3d41dc31bf2c89ae0c125b68abc0d81989bb3f03 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 31 Mar 2026 17:44:33 +0000 Subject: [PATCH 020/148] Update --- gigl/distributed/base_dist_loader.py | 7 - gigl/distributed/dist_ablp_neighborloader.py | 17 ++ gigl/distributed/dist_dataset.py | 24 ++- gigl/distributed/dist_ppr_sampler.py | 74 ++++++--- gigl/distributed/dist_sampling_producer.py | 49 +----- .../distributed/distributed_neighborloader.py | 17 ++ gigl/distributed/sampler_options.py | 6 +- gigl/distributed/utils/degree.py | 153 ++++++------------ tests/unit/distributed/utils/degree_test.py | 58 +++---- 9 files changed, 166 insertions(+), 239 deletions(-) diff --git a/gigl/distributed/base_dist_loader.py b/gigl/distributed/base_dist_loader.py index 4823813f1..ed0783ef6 100644 --- a/gigl/distributed/base_dist_loader.py +++ b/gigl/distributed/base_dist_loader.py @@ -566,13 +566,6 @@ def _init_colocated_connections( self._channel = producer.output_channel self._mp_producer = producer - # Run distributed collectives (e.g. degree tensor all_reduce for PPR) - # BEFORE the staggered sleep. Collectives require all ranks to - # participate simultaneously; sleeping first would cause all ranks to - # exit the collective together and then proceed to worker spawning at - # the same time, nullifying the stagger. - producer.pre_init_collectives() - # Staggered init — sleep proportional to local_rank to avoid # concurrent initialization spikes that cause CPU memory OOM. logger.info( diff --git a/gigl/distributed/dist_ablp_neighborloader.py b/gigl/distributed/dist_ablp_neighborloader.py index f96fd3bc0..8c86c1c3d 100644 --- a/gigl/distributed/dist_ablp_neighborloader.py +++ b/gigl/distributed/dist_ablp_neighborloader.py @@ -359,6 +359,22 @@ def __init__( assert isinstance(dataset, DistDataset) assert isinstance(worker_options, MpDistSamplingWorkerOptions) channel = BaseDistLoader.create_colocated_channel(worker_options) + # Compute degree tensors here, before the producer is constructed and + # before the staggered sleep in _init_colocated_connections. The + # all_reduce requires all ranks to participate simultaneously; deferring + # it to after the sleep would negate the stagger on worker spawning. + if isinstance(sampler_options, PPRSamplerOptions): + degree_tensors = dataset.degree_tensor + if isinstance(degree_tensors, dict): + logger.info( + f"Pre-computed degree tensors for PPR sampling across {len(degree_tensors)} edge types." + ) + else: + logger.info( + f"Pre-computed degree tensor for PPR sampling with {degree_tensors.size(0)} nodes." + ) + else: + degree_tensors = None producer: Union[ DistSamplingProducer, Callable[..., int] ] = DistSamplingProducer( @@ -368,6 +384,7 @@ def __init__( worker_options=worker_options, channel=channel, sampler_options=sampler_options, + degree_tensors=degree_tensors, ) else: producer = DistServer.create_sampling_producer diff --git a/gigl/distributed/dist_dataset.py b/gigl/distributed/dist_dataset.py index 20436f4bc..f495a6d96 100644 --- a/gigl/distributed/dist_dataset.py +++ b/gigl/distributed/dist_dataset.py @@ -78,7 +78,7 @@ def __init__( Union[FeatureInfo, dict[EdgeType, FeatureInfo]] ] = None, degree_tensor: Optional[ - Union[torch.Tensor, dict[NodeType, torch.Tensor]] + Union[torch.Tensor, dict[EdgeType, torch.Tensor]] ] = None, ) -> None: """ @@ -104,7 +104,7 @@ def __init__( Note this will be None in the homogeneous case if the data has no node features, or will only contain node types with node features in the heterogeneous case. edge_feature_info: Optional[Union[FeatureInfo, dict[EdgeType, FeatureInfo]]]: Dimension of edge features and its data type, will be a dict if heterogeneous. Note this will be None in the homogeneous case if the data has no edge features, or will only contain edge types with edge features in the heterogeneous case. - degree_tensor: Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]]: Pre-computed degree tensor. Lazily computed on first access via the degree_tensor property. + degree_tensor: Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]]: Pre-computed degree tensor. Lazily computed on first access via the degree_tensor property. """ self._rank: int = rank self._world_size: int = world_size @@ -141,7 +141,7 @@ def __init__( self._edge_feature_info = edge_feature_info self._degree_tensor: Optional[ - Union[torch.Tensor, dict[NodeType, torch.Tensor]] + Union[torch.Tensor, dict[EdgeType, torch.Tensor]] ] = degree_tensor # TODO (mkolodner-sc): Modify so that we don't need to rely on GLT's base variable naming (i.e. partition_idx, num_partitions) in favor of more clear @@ -300,7 +300,7 @@ def edge_feature_info( @property def degree_tensor( self, - ) -> Union[torch.Tensor, dict[NodeType, torch.Tensor]]: + ) -> Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: """ Lazily compute and return the degree tensor for the graph. @@ -308,19 +308,15 @@ def degree_tensor( all-reduce to aggregate across all machines. Requires torch.distributed to be initialized. - For heterogeneous graphs, degrees are summed across all edge types sharing - the same anchor node type (determined by ``self._edge_dir``), yielding one - ``int16`` tensor per node type rather than one per edge type. - Over-counting correction (for processes sharing the same data on the same machine) is handled automatically by detecting the distributed topology. The result is cached for subsequent accesses. Returns: - Union[torch.Tensor, dict[NodeType, torch.Tensor]]: The aggregated degree tensor. + Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: The aggregated degree tensor. - For homogeneous graphs: A tensor of shape [num_nodes]. - - For heterogeneous graphs: A dict mapping NodeType to ``int16`` degree tensors. + - For heterogeneous graphs: A dict mapping EdgeType to degree tensors. Raises: RuntimeError: If torch.distributed is not initialized. @@ -330,9 +326,7 @@ def degree_tensor( if self.graph is None: raise ValueError("Dataset graph is None. Cannot compute degrees.") - self._degree_tensor = compute_and_broadcast_degree_tensor( - self.graph, edge_dir=self._edge_dir - ) + self._degree_tensor = compute_and_broadcast_degree_tensor(self.graph) return self._degree_tensor @property @@ -863,7 +857,7 @@ def share_ipc( Optional[Union[int, dict[NodeType, int]]], Optional[Union[FeatureInfo, dict[NodeType, FeatureInfo]]], Optional[Union[FeatureInfo, dict[EdgeType, FeatureInfo]]], - Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]], + Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]], ]: """ Serializes the member variables of the DistDatasetClass @@ -885,7 +879,7 @@ def share_ipc( Optional[Union[int, dict[NodeType, int]]]: Number of test nodes on the current machine. Will be a dict if heterogeneous. Optional[Union[FeatureInfo, dict[NodeType, FeatureInfo]]]: Node feature dim and its data type, will be a dict if heterogeneous Optional[Union[FeatureInfo, dict[EdgeType, FeatureInfo]]]: Edge feature dim and its data type, will be a dict if heterogeneous - Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]]: Degree tensors, will be a dict if heterogeneous + Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]]: Degree tensors, will be a dict if heterogeneous """ # TODO (mkolodner-sc): Investigate moving share_memory calls to the build() function diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 34cb1661b..17673a72d 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -103,7 +103,7 @@ def __init__( max_ppr_nodes: int = 50, num_neighbors_per_hop: int = 100_000, total_degree_dtype: torch.dtype = torch.int32, - degree_tensors: Union[torch.Tensor, dict[NodeType, torch.Tensor]], + degree_tensors: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], **kwargs, ): super().__init__(*args, **kwargs) @@ -144,45 +144,69 @@ def __init__( ] self._is_homogeneous = True - # The dataset pre-aggregates degrees per node type as int16. - # _build_total_degree_tensors reindexes by node type with no further casting. + # Precompute total degree per node type: the sum of degrees across all + # edge types traversable from that node type. This is a graph-level + # property used on every PPR iteration, so computing it once at init + # avoids per-node summation and cache lookups in the hot loop. + # TODO (mkolodner-sc): This trades memory for throughput — we + # materialize a tensor per node type to avoid recomputing total degree + # on every neighbor during sampling. Computing it here (rather than in + # the dataset) also keeps the door open for edge-specific degree + # strategies. If memory becomes a bottleneck, revisit this. self._node_type_to_total_degree: dict[ NodeType, torch.Tensor - ] = self._build_total_degree_tensors(degree_tensors) + ] = self._build_total_degree_tensors(degree_tensors, total_degree_dtype) def _build_total_degree_tensors( self, - degree_tensors: Union[torch.Tensor, dict[NodeType, torch.Tensor]], + degree_tensors: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], + dtype: torch.dtype, ) -> dict[NodeType, torch.Tensor]: - """Reindex pre-aggregated per-node-type degree tensors for use in the PPR loop. + """Build total-degree tensors by summing per-edge-type degrees for each node type. - The dataset provides degrees already summed across edge types per node type - (as ``int16``). This method maps those tensors into the internal node-type - keying used by the sampler, with no further summation or dtype casting. + For homogeneous graphs, the total degree is just the single degree tensor. + For heterogeneous graphs, it sums degree tensors across all edge types + traversable from each node type, padding shorter tensors with zeros. Args: - degree_tensors: Per-node-type degree tensors from the dataset, already - aggregated across edge types. + degree_tensors: Per-edge-type degree tensors from the dataset. + dtype: Dtype for the output tensors. Returns: - Dict mapping node type to a 1-D degree tensor. - - Raises: - ValueError: If a required node type is absent from ``degree_tensors``. + Dict mapping node type to a 1-D tensor of total degrees. """ + result: dict[NodeType, torch.Tensor] = {} + if self._is_homogeneous: assert isinstance(degree_tensors, torch.Tensor) - return {_PPR_HOMOGENEOUS_NODE_TYPE: degree_tensors} + # Single edge type: degree values fit directly in the target dtype. + result[_PPR_HOMOGENEOUS_NODE_TYPE] = degree_tensors.to(dtype) + else: + assert isinstance(degree_tensors, dict) + dtype_max = torch.iinfo(dtype).max + for node_type, edge_types in self._node_type_to_edge_types.items(): + max_len = 0 + for et in edge_types: + if et not in degree_tensors: + raise ValueError( + f"Edge type {et} not found in degree tensors. " + f"Available: {list(degree_tensors.keys())}" + ) + max_len = max(max_len, len(degree_tensors[et])) + + # Each degree tensor is indexed by node ID (derived from CSR + # indptr), so index i in every edge type's tensor refers to + # the same node. Element-wise summation gives the total degree + # per node across all edge types. Shorter tensors are padded + # implicitly (only the first len(et_degrees) entries are added). + # Sum in int64: aggregate degrees are bounded by partition size + # and fit comfortably within int64 range in practice. + summed = torch.zeros(max_len, dtype=torch.int64) + for et in edge_types: + et_degrees = degree_tensors[et] + summed[: len(et_degrees)] += et_degrees.to(torch.int64) + result[node_type] = summed.clamp(max=dtype_max).to(dtype) - assert isinstance(degree_tensors, dict) - result: dict[NodeType, torch.Tensor] = {} - for node_type in self._node_type_to_edge_types: - if node_type not in degree_tensors: - raise ValueError( - f"Node type '{node_type}' not found in degree tensors. " - f"Available: {list(degree_tensors.keys())}" - ) - result[node_type] = degree_tensors[node_type] return result def _get_total_degree(self, node_id: int, node_type: NodeType) -> int: diff --git a/gigl/distributed/dist_sampling_producer.py b/gigl/distributed/dist_sampling_producer.py index 1294d2d4d..78aaeb388 100644 --- a/gigl/distributed/dist_sampling_producer.py +++ b/gigl/distributed/dist_sampling_producer.py @@ -29,14 +29,13 @@ SamplingConfig, SamplingType, ) -from graphlearn_torch.typing import EdgeType, NodeType +from graphlearn_torch.typing import EdgeType from graphlearn_torch.utils import seed_everything from torch._C import _set_worker_signal_handlers from torch.utils.data.dataloader import DataLoader from torch.utils.data.dataset import Dataset from gigl.common.logger import Logger -from gigl.distributed.dist_dataset import DistDataset as GiglDistDataset from gigl.distributed.dist_neighbor_sampler import DistNeighborSampler from gigl.distributed.dist_ppr_sampler import DistPPRNeighborSampler from gigl.distributed.sampler_options import ( @@ -60,7 +59,7 @@ def _sampling_worker_loop( sampling_completed_worker_count, # mp.Value mp_barrier: Barrier, sampler_options: SamplerOptions, - degree_tensors: Optional[Union[torch.Tensor, dict[NodeType, torch.Tensor]]], + degree_tensors: Optional[Union[torch.Tensor, dict[EdgeType, torch.Tensor]]], ): dist_sampler = None try: @@ -212,50 +211,16 @@ def __init__( worker_options: MpDistSamplingWorkerOptions, channel: ChannelBase, sampler_options: SamplerOptions, + degree_tensors: Optional[ + Union[torch.Tensor, dict[EdgeType, torch.Tensor]] + ] = None, ): super().__init__(data, sampler_input, sampling_config, worker_options, channel) self._sampler_options = sampler_options - - def pre_init_collectives(self) -> None: - """Run distributed collectives that must complete before the staggered init sleep. - - ``init()`` calls ``self.data.degree_tensor``, which triggers a - ``torch.distributed.all_reduce``. Collectives require all ranks to - participate simultaneously. If that collective runs inside ``init()`` - (after the staggered sleep), every rank exits the collective at the same - instant and proceeds to worker spawning together, negating the stagger. - - Call this before the staggered sleep so all ranks complete the collective - together, then the sleep staggering applies only to the expensive worker- - spawn step. The result is cached on the dataset; ``init()`` reuses it - without re-running the collective. - """ - if isinstance(self._sampler_options, PPRSamplerOptions): - assert isinstance(self.data, GiglDistDataset) - _ = self.data.degree_tensor + self._degree_tensors = degree_tensors def init(self): r"""Create the subprocess pool. Init samplers and rpc server.""" - # Extract degree tensors before spawning workers. Worker subprocesses - # only initialize RPC (not torch.distributed), so the lazy degree - # computation on GiglDistDataset would fail there. Computing here — - # where torch.distributed IS initialized — lets the tensor be shared - # to workers via IPC. - degree_tensors: Optional[ - Union[torch.Tensor, dict[NodeType, torch.Tensor]] - ] = None - if isinstance(self._sampler_options, PPRSamplerOptions): - assert isinstance(self.data, GiglDistDataset) - degree_tensors = self.data.degree_tensor - if isinstance(degree_tensors, dict): - logger.info( - f"Pre-computed degree tensors for PPR sampling across {len(degree_tensors)} node types." - ) - else: - logger.info( - f"Pre-computed degree tensor for PPR sampling with {degree_tensors.size(0)} nodes." - ) - if self.sampling_config.seed is not None: seed_everything(self.sampling_config.seed) if not self.sampling_config.shuffle: @@ -284,7 +249,7 @@ def init(self): self.sampling_completed_worker_count, barrier, self._sampler_options, - degree_tensors, + self._degree_tensors, ), ) w.daemon = True diff --git a/gigl/distributed/distributed_neighborloader.py b/gigl/distributed/distributed_neighborloader.py index e47075343..2d3b82e9a 100644 --- a/gigl/distributed/distributed_neighborloader.py +++ b/gigl/distributed/distributed_neighborloader.py @@ -268,6 +268,22 @@ def __init__( assert isinstance(dataset, DistDataset) assert isinstance(worker_options, MpDistSamplingWorkerOptions) channel = BaseDistLoader.create_colocated_channel(worker_options) + # Compute degree tensors here, before the producer is constructed and + # before the staggered sleep in _init_colocated_connections. The + # all_reduce requires all ranks to participate simultaneously; deferring + # it to after the sleep would negate the stagger on worker spawning. + if isinstance(sampler_options, PPRSamplerOptions): + degree_tensors = dataset.degree_tensor + if isinstance(degree_tensors, dict): + logger.info( + f"Pre-computed degree tensors for PPR sampling across {len(degree_tensors)} edge types." + ) + else: + logger.info( + f"Pre-computed degree tensor for PPR sampling with {degree_tensors.size(0)} nodes." + ) + else: + degree_tensors = None producer: Union[ DistSamplingProducer, Callable[..., int] ] = DistSamplingProducer( @@ -277,6 +293,7 @@ def __init__( worker_options=worker_options, channel=channel, sampler_options=sampler_options, + degree_tensors=degree_tensors, ) else: producer = GiglDistServer.create_sampling_producer diff --git a/gigl/distributed/sampler_options.py b/gigl/distributed/sampler_options.py index b3165b2af..d87a83d52 100644 --- a/gigl/distributed/sampler_options.py +++ b/gigl/distributed/sampler_options.py @@ -56,9 +56,9 @@ class PPRSamplerOptions: num_neighbors_per_hop: Maximum number of neighbors fetched per node per edge type during PPR traversal. Set large to approximate fetching all neighbors. - total_degree_dtype: Retained for backwards compatibility; currently unused. - Degree tensors are stored as ``int16`` and no dtype conversion is - applied in the sampler. + total_degree_dtype: Dtype for precomputed total-degree tensors. Defaults + to ``torch.int32``, which supports total degrees up to ~2 billion. + Use a larger dtype if nodes have exceptionally high aggregate degrees. """ alpha: float = 0.5 diff --git a/gigl/distributed/utils/degree.py b/gigl/distributed/utils/degree.py index 188dfa4de..e5cb29cb9 100644 --- a/gigl/distributed/utils/degree.py +++ b/gigl/distributed/utils/degree.py @@ -27,7 +27,7 @@ import torch from graphlearn_torch.data import Graph -from torch_geometric.typing import EdgeType, NodeType +from torch_geometric.typing import EdgeType from gigl.common.logger import Logger from gigl.distributed.utils.device import get_device_from_process_group @@ -39,34 +39,30 @@ def compute_and_broadcast_degree_tensor( graph: Union[Graph, dict[EdgeType, Graph]], - edge_dir: str, -) -> Union[torch.Tensor, dict[NodeType, torch.Tensor]]: +) -> Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: """ Compute node degrees from a graph and aggregate across all machines. - For heterogeneous graphs, degrees are summed across all edge types sharing - the same anchor node type (source for ``edge_dir="out"``, destination for - ``edge_dir="in"``), then all-reduced across ranks. The result is one - ``int16`` tensor per anchor node type rather than one per edge type, - reducing both stored memory and the number of all-reduce calls. + Computes degrees from the CSR row pointers (indptr) and performs all-reduce + to aggregate across ranks. Over-counting correction (for processes sharing the same data) is handled automatically by detecting the distributed topology. Args: graph: A Graph (homogeneous) or dict[EdgeType, Graph] (heterogeneous). - edge_dir: ``"out"`` to group by source node type (out-degree); - ``"in"`` to group by destination node type (in-degree). + For heterogeneous graphs, label edge types are automatically excluded + from the computation — they are supervision edges and should not + contribute to node degree for graph traversal algorithms like PPR. Returns: - Union[torch.Tensor, dict[NodeType, torch.Tensor]]: The aggregated degree tensors. + Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: The aggregated degree tensors. - For homogeneous graphs: A tensor of shape [num_nodes]. - - For heterogeneous graphs: A dict mapping NodeType to ``int16`` degree tensors, - where each entry is the total degree across all edge types for that anchor node type. + - For heterogeneous graphs: A dict mapping non-label EdgeType to degree tensors. Raises: RuntimeError: If torch.distributed is not initialized. - ValueError: If topology is unavailable for a homogeneous graph. + ValueError: If topology is unavailable. """ if not torch.distributed.is_initialized(): raise RuntimeError( @@ -79,10 +75,24 @@ def compute_and_broadcast_degree_tensor( if topo is None or topo.indptr is None: raise ValueError("Topology/indptr not available for graph.") local_degrees: Union[ - torch.Tensor, dict[NodeType, torch.Tensor] + torch.Tensor, dict[EdgeType, torch.Tensor] ] = _compute_degrees_from_indptr(topo.indptr) else: - local_degrees = _compute_hetero_degrees_by_node_type(graph, edge_dir) + local_dict: dict[EdgeType, torch.Tensor] = {} + for edge_type, edge_graph in graph.items(): + # Label edge types are supervision edges and should not contribute + # to node degree for graph traversal algorithms like PPR. + if is_label_edge_type(edge_type): + continue + topo = edge_graph.topo + if topo is None or topo.indptr is None: + logger.warning( + f"Topology/indptr not available for edge type {edge_type}, using empty tensor." + ) + local_dict[edge_type] = torch.empty(0, dtype=torch.int16) + else: + local_dict[edge_type] = _compute_degrees_from_indptr(topo.indptr) + local_degrees = local_dict # All-reduce across ranks (over-counting correction handled internally) result = _all_reduce_degrees(local_degrees) @@ -96,90 +106,19 @@ def compute_and_broadcast_degree_tensor( else: logger.info("Graph contained 0 nodes when computing degrees") else: - for node_type, degrees in result.items(): + for edge_type, degrees in result.items(): if degrees.numel() > 0: logger.info( - f"{node_type}: {degrees.size(0)} nodes, max={degrees.max().item()}, min={degrees.min().item()}" + f"{edge_type}: {degrees.size(0)} nodes, max={degrees.max().item()}, min={degrees.min().item()}" ) else: logger.info( - f"Graph contained 0 nodes for node type {node_type} when computing degrees" + f"Graph contained 0 nodes for edge type {edge_type} when computing degrees" ) return result -def _compute_hetero_degrees_by_node_type( - graph: dict[EdgeType, Graph], - edge_dir: str, -) -> dict[NodeType, torch.Tensor]: - """Sum per-edge-type degrees into per-anchor-node-type totals. - - Label edge types (ABLP supervision edges) are excluded — they should not - contribute to degree counts used in PPR, matching the sampler's own exclusion. - - Uses a two-pass approach to avoid dynamic accumulator resizing: - - - Pass 1: compute ``int32`` degrees per edge type and record the maximum - node count per anchor type (to pre-size the accumulator). - - Pass 2: allocate one ``int32`` accumulator per anchor type and sum. - - Returns ``int32`` tensors; the caller is responsible for clamping to - ``int16`` after the all-reduce (see ``_all_reduce_degrees``). - - All anchor node types derived from non-label ``graph.keys()`` are present in - the output (with size-0 tensors for types whose ``indptr`` is unavailable), - ensuring symmetric participation in the subsequent all-reduce. - - Args: - graph: Heterogeneous graph mapping EdgeType to Graph. - edge_dir: ``"out"`` to anchor on source node type; ``"in"`` to anchor - on destination node type. - - Returns: - dict[NodeType, torch.Tensor]: ``int32`` total-degree tensor per anchor node type. - """ - # All anchor node types must appear in the output so the all_reduce is - # symmetric across ranks, even if this rank has no edges for a given type. - # Label edge types are excluded — they represent ABLP supervision edges, not - # structural neighbors, and should not contribute to degree counts used in PPR. - anchor_ntypes: set[NodeType] = { - etype[-1] if edge_dir == "in" else etype[0] - for etype in graph.keys() - if not is_label_edge_type(etype) - } - - # Pass 1: compute int32 degrees per valid edge type and track max node - # count per anchor type. int32 is sufficient: per-node degrees are always - # well below int32 max for any realistic graph. - et_degrees_i32: dict[EdgeType, torch.Tensor] = {} - max_sizes: dict[NodeType, int] = {ntype: 0 for ntype in anchor_ntypes} - for edge_type, edge_graph in graph.items(): - if is_label_edge_type(edge_type): - continue - anchor_ntype: NodeType = edge_type[-1] if edge_dir == "in" else edge_type[0] - topo = edge_graph.topo - if topo is None or topo.indptr is None: - logger.warning( - f"Topology/indptr not available for edge type {edge_type}, skipping." - ) - continue - degrees_i32 = (topo.indptr[1:] - topo.indptr[:-1]).to(torch.int32) - et_degrees_i32[edge_type] = degrees_i32 - max_sizes[anchor_ntype] = max(max_sizes[anchor_ntype], len(degrees_i32)) - - # Pass 2: allocate accumulators once (sized from pass 1) and sum. - accumulators: dict[NodeType, torch.Tensor] = { - ntype: torch.zeros(size, dtype=torch.int32) - for ntype, size in max_sizes.items() - } - for edge_type, degrees_i32 in et_degrees_i32.items(): - anchor_ntype = edge_type[-1] if edge_dir == "in" else edge_type[0] - accumulators[anchor_ntype][: len(degrees_i32)] += degrees_i32 - - return accumulators - - def _pad_to_size(tensor: torch.Tensor, target_size: int) -> torch.Tensor: """Pad tensor with zeros to reach target_size.""" if tensor.size(0) >= target_size: @@ -204,12 +143,12 @@ def _compute_degrees_from_indptr(indptr: torch.Tensor) -> torch.Tensor: def _all_reduce_degrees( - local_degrees: Union[torch.Tensor, dict[NodeType, torch.Tensor]], -) -> Union[torch.Tensor, dict[NodeType, torch.Tensor]]: + local_degrees: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], +) -> Union[torch.Tensor, dict[EdgeType, torch.Tensor]]: """All-reduce degree tensors across ranks, handling both homogeneous and heterogeneous cases. - For heterogeneous graphs, iterates over the node types in local_degrees. All partitions - are expected to have entries for all node types (even if some have empty tensors). + For heterogeneous graphs, iterates over the edge types in local_degrees. All partitions + are expected to have entries for all edge types (even if some have empty tensors). Moves tensors to GPU for the all-reduce if using NCCL backend (which requires CUDA), otherwise keeps tensors on CPU (for Gloo backend). @@ -233,12 +172,12 @@ def _all_reduce_degrees( IP addresses, then divides by that count to correct the over-counting. Args: - local_degrees: Either a single tensor (homogeneous) or dict mapping NodeType + local_degrees: Either a single tensor (homogeneous) or dict mapping EdgeType to tensors (heterogeneous). For heterogeneous graphs, all partitions must - have entries for all node types. + have entries for all edge types. Returns: - Aggregated degree tensors in the same format as input, stored as ``int16``. + Aggregated degree tensors in the same format as input. Raises: RuntimeError: If torch.distributed is not initialized. @@ -264,24 +203,22 @@ def reduce_tensor(tensor: torch.Tensor) -> torch.Tensor: torch.distributed.all_reduce(local_size, op=torch.distributed.ReduceOp.MAX) max_size = int(local_size.item()) - # Pad and convert to int32 for the all-reduce (int16 is not supported). - # int32 is sufficient: the raw sum across W ranks is at most W * max_degree, - # which fits comfortably in int32 for any realistic world size and degree. - padded = _pad_to_size(tensor, max_size).to(torch.int32).to(device) + # Pad, convert to int64 (all_reduce doesn't support int16), move to device + padded = _pad_to_size(tensor, max_size).to(torch.int64).to(device) torch.distributed.all_reduce(padded, op=torch.distributed.ReduceOp.SUM) - # Correct for over-counting, move back to CPU, and clamp to int16. - # TODO (mkolodner-sc): Potentially want to parameterize this in the future if we want degrees higher than the int16 max. + # Correct for over-counting, move back to CPU, and clamp to int16 + # TODO (mkolodner-sc): Potentially want to paramaterize this in the future if we want degrees higher than the int16 max. return _clamp_to_int16((padded // local_world_size).cpu()) # Homogeneous case if isinstance(local_degrees, torch.Tensor): return reduce_tensor(local_degrees) - # Heterogeneous case: all-reduce each node type. - # Sort node types for deterministic ordering across ranks. - result: dict[NodeType, torch.Tensor] = {} - for node_type in sorted(local_degrees.keys()): - result[node_type] = reduce_tensor(local_degrees[node_type]) + # Heterogeneous case: all-reduce each edge type + # Sort edge types for deterministic ordering across ranks + result: dict[EdgeType, torch.Tensor] = {} + for edge_type in sorted(local_degrees.keys()): + result[edge_type] = reduce_tensor(local_degrees[edge_type]) return result diff --git a/tests/unit/distributed/utils/degree_test.py b/tests/unit/distributed/utils/degree_test.py index 16f334509..6836e4581 100644 --- a/tests/unit/distributed/utils/degree_test.py +++ b/tests/unit/distributed/utils/degree_test.py @@ -60,7 +60,7 @@ def test_homogeneous_graph(self): dataset = create_homogeneous_dataset(edge_index=edge_index) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") + result = compute_and_broadcast_degree_tensor(dataset.graph) assert isinstance(result, torch.Tensor) expected = _compute_expected_degrees_from_edge_index(edge_index, num_nodes) @@ -68,28 +68,20 @@ def test_homogeneous_graph(self): self.assert_tensor_equality(result, expected) def test_heterogeneous_graph(self): - """Test degree computation for a heterogeneous graph. - - Result is keyed by anchor node type (source for edge_dir="out"), not edge type. - Degrees are summed across all edge types sharing the same anchor node type. - """ + """Test degree computation for a heterogeneous graph.""" edge_indices = DEFAULT_HETEROGENEOUS_EDGE_INDICES dataset = create_heterogeneous_dataset(edge_indices=edge_indices) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") + result = compute_and_broadcast_degree_tensor(dataset.graph) assert isinstance(result, dict) - expected_node_types = {etype[0] for etype in edge_indices.keys()} - self.assertEqual(set(result.keys()), expected_node_types) + self.assertEqual(set(result.keys()), set(edge_indices.keys())) - # For the default test data each source node type maps to exactly one edge type, - # so per-node-type degrees equal per-edge-type degrees. for edge_type, edge_index in edge_indices.items(): - src_node_type = edge_type[0] num_nodes = int(edge_index[0].max().item() + 1) expected = _compute_expected_degrees_from_edge_index(edge_index, num_nodes) - self.assert_tensor_equality(result[src_node_type], expected) + self.assert_tensor_equality(result[edge_type], expected) def test_heterogeneous_graph_with_missing_topology(self): """Test that edge types with missing topology get empty tensors. @@ -121,18 +113,16 @@ def test_heterogeneous_graph_with_missing_topology(self): # Manually set one graph's topology to None to test the edge case dataset.graph[edge_type_without_topo].topo = None - result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") + result = compute_and_broadcast_degree_tensor(dataset.graph) assert isinstance(result, dict) - # Keys are source node types (anchor for edge_dir="out"), not edge types. - expected_node_types = {etype[0] for etype in edge_types} - self.assertEqual(set(result.keys()), expected_node_types) + self.assertEqual(set(result.keys()), set(edge_types)) - # Edge type with topology: anchor node type should have computed degrees. - self.assert_tensor_equality(result[edge_type_with_topo[0]], expected_degrees) + # Edge type with topology should have computed degrees + self.assert_tensor_equality(result[edge_type_with_topo], expected_degrees) - # Edge type without topology: anchor node type should have empty tensor. - self.assertEqual(result[edge_type_without_topo[0]].numel(), 0) + # Edge type without topology should have empty tensor + self.assertEqual(result[edge_type_without_topo].numel(), 0) def _run_local_world_size_correction_homogeneous( @@ -152,7 +142,7 @@ def _run_local_world_size_correction_homogeneous( try: dataset = create_homogeneous_dataset(edge_index=edge_index) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") + result = compute_and_broadcast_degree_tensor(dataset.graph) assert isinstance(result, torch.Tensor) assert_tensor_equality(result, expected_degrees) @@ -167,10 +157,7 @@ def _run_local_world_size_correction_heterogeneous( edge_indices: dict, expected_degrees: dict, ) -> None: - """Worker function for multi-process local_world_size correction test (heterogeneous). - - expected_degrees must be keyed by node type (anchor for edge_dir="out"). - """ + """Worker function for multi-process local_world_size correction test (heterogeneous).""" dist.init_process_group( backend="gloo", init_method=init_method, @@ -180,12 +167,12 @@ def _run_local_world_size_correction_heterogeneous( try: dataset = create_heterogeneous_dataset(edge_indices=edge_indices) assert dataset.graph is not None - result = compute_and_broadcast_degree_tensor(dataset.graph, edge_dir="out") + result = compute_and_broadcast_degree_tensor(dataset.graph) assert isinstance(result, dict) assert set(result.keys()) == set(expected_degrees.keys()) - for node_type, expected in expected_degrees.items(): - assert_tensor_equality(result[node_type], expected) + for edge_type, expected in expected_degrees.items(): + assert_tensor_equality(result[edge_type], expected) finally: dist.destroy_process_group() @@ -217,16 +204,13 @@ def test_local_world_size_correction_heterogeneous(self): """Test over-counting correction for heterogeneous graphs with 2 processes.""" edge_indices = DEFAULT_HETEROGENEOUS_EDGE_INDICES - # Build expected degrees keyed by source node type (anchor for edge_dir="out"). - # For the default test data each source node type maps to exactly one edge type. expected_degrees = {} for edge_type, edge_index in edge_indices.items(): - src_node_type = edge_type[0] num_nodes = int(edge_index[0].max().item() + 1) raw_degrees = _compute_expected_degrees_from_edge_index( edge_index, num_nodes ) - expected_degrees[src_node_type] = raw_degrees + expected_degrees[edge_type] = raw_degrees init_method = get_process_group_init_method() mp.spawn( @@ -279,16 +263,12 @@ def test_degree_tensor_heterogeneous(self): result = dataset.degree_tensor assert isinstance(result, dict) - # degree_tensor is keyed by node type (anchor for dataset's edge_dir="out"), not edge type. - expected_node_types = {etype[0] for etype in edge_indices.keys()} - self.assertEqual(set(result.keys()), expected_node_types) + self.assertEqual(set(result.keys()), set(edge_indices.keys())) - # For the default test data each source node type maps to exactly one edge type. for edge_type, edge_index in edge_indices.items(): - src_node_type = edge_type[0] num_nodes = int(edge_index[0].max().item() + 1) expected = _compute_expected_degrees_from_edge_index(edge_index, num_nodes) - self.assert_tensor_equality(result[src_node_type], expected) + self.assert_tensor_equality(result[edge_type], expected) class TestHelperFunctions(TestCase): From 04cee0c96aeb426fa8d05829daef209aa5cf348a Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 31 Mar 2026 18:22:30 +0000 Subject: [PATCH 021/148] Fix for gs mode --- gigl/distributed/graph_store/dist_server.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/gigl/distributed/graph_store/dist_server.py b/gigl/distributed/graph_store/dist_server.py index 2fba2d93d..bd991c5eb 100644 --- a/gigl/distributed/graph_store/dist_server.py +++ b/gigl/distributed/graph_store/dist_server.py @@ -39,7 +39,7 @@ FetchNodesRequest, ) from gigl.distributed.sampler import ABLPNodeSamplerInput -from gigl.distributed.sampler_options import SamplerOptions +from gigl.distributed.sampler_options import PPRSamplerOptions, SamplerOptions from gigl.distributed.utils.neighborloader import shard_nodes_by_process from gigl.src.common.types.graph_data import EdgeType, NodeType from gigl.types.graph import FeatureInfo, select_label_edge_types @@ -485,6 +485,16 @@ def create_sampling_producer( buffer = ShmChannel( worker_options.buffer_capacity, worker_options.buffer_size ) + # Degree tensors for PPR must be computed before constructing + # the producer. The all_reduce inside degree_tensor requires + # all ranks to participate simultaneously and cannot run inside + # worker subprocesses (which only initialize RPC, not + # torch.distributed). + degree_tensors = ( + self.dataset.degree_tensor + if isinstance(sampler_options, PPRSamplerOptions) + else None + ) producer = DistSamplingProducer( data=self.dataset, sampler_input=sampler_input, @@ -492,6 +502,7 @@ def create_sampling_producer( worker_options=worker_options, channel=buffer, sampler_options=sampler_options, + degree_tensors=degree_tensors, ) producer_start_time = time.monotonic() producer.init() From 99fdef2a1a3b8ec8c1d65d7f05946bd70787800f Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 31 Mar 2026 20:40:58 +0000 Subject: [PATCH 022/148] Address comment --- gigl/distributed/base_dist_loader.py | 56 ++++++++++++++++++- gigl/distributed/dist_ablp_neighborloader.py | 23 +------- .../distributed/distributed_neighborloader.py | 23 +------- 3 files changed, 59 insertions(+), 43 deletions(-) diff --git a/gigl/distributed/base_dist_loader.py b/gigl/distributed/base_dist_loader.py index ed0783ef6..b0ce59afd 100644 --- a/gigl/distributed/base_dist_loader.py +++ b/gigl/distributed/base_dist_loader.py @@ -26,6 +26,7 @@ from graphlearn_torch.distributed.dist_client import async_request_server from graphlearn_torch.distributed.rpc import rpc_is_initialized from graphlearn_torch.sampler import ( + EdgeSamplerInput, NodeSamplerInput, RemoteSamplerInput, SamplingConfig, @@ -42,7 +43,7 @@ from gigl.distributed.dist_sampling_producer import DistSamplingProducer from gigl.distributed.graph_store.dist_server import DistServer from gigl.distributed.graph_store.remote_dist_dataset import RemoteDistDataset -from gigl.distributed.sampler_options import SamplerOptions +from gigl.distributed.sampler_options import PPRSamplerOptions, SamplerOptions from gigl.distributed.utils.neighborloader import ( DatasetSchema, patch_fanout_for_sampling, @@ -388,6 +389,59 @@ def create_colocated_channel( channel.pin_memory() return channel + @staticmethod + def create_mp_producer( + dataset: DistDataset, + sampler_input: Union[NodeSamplerInput, EdgeSamplerInput], + sampling_config: SamplingConfig, + worker_options: MpDistSamplingWorkerOptions, + sampler_options: SamplerOptions, + ) -> DistSamplingProducer: + """Create a colocated-mode DistSamplingProducer with pre-computed degree tensors. + + Creates the shared-memory channel and, for PPR sampling, pre-computes + degree tensors via all-reduce before constructing the producer. The + all-reduce must happen here — before the staggered sleep in + ``_init_colocated_connections`` — so that all ranks complete the + collective together and the stagger applies only to worker spawning. + + Args: + dataset: The local DistDataset for this rank. + sampler_input: Node or edge sampler input (ABLPNodeSamplerInput is + also accepted as it extends NodeSamplerInput). + sampling_config: Sampling configuration. + worker_options: Colocated worker options (must be fully configured). + sampler_options: Controls which sampler class is instantiated. + + Returns: + A fully constructed DistSamplingProducer, ready to be passed to + ``_init_colocated_connections``. + """ + channel = BaseDistLoader.create_colocated_channel(worker_options) + if isinstance(sampler_options, PPRSamplerOptions): + degree_tensors = dataset.degree_tensor + if isinstance(degree_tensors, dict): + logger.info( + f"Pre-computed degree tensors for PPR sampling across " + f"{len(degree_tensors)} edge types." + ) + else: + logger.info( + f"Pre-computed degree tensor for PPR sampling with " + f"{degree_tensors.size(0)} nodes." + ) + else: + degree_tensors = None + return DistSamplingProducer( + data=dataset, + sampler_input=sampler_input, + sampling_config=sampling_config, + worker_options=worker_options, + channel=channel, + sampler_options=sampler_options, + degree_tensors=degree_tensors, + ) + @staticmethod def initialize_colocated_sampling_worker( *, diff --git a/gigl/distributed/dist_ablp_neighborloader.py b/gigl/distributed/dist_ablp_neighborloader.py index 8c86c1c3d..f9efd01a0 100644 --- a/gigl/distributed/dist_ablp_neighborloader.py +++ b/gigl/distributed/dist_ablp_neighborloader.py @@ -358,33 +358,14 @@ def __init__( if self._sampling_cluster_setup == SamplingClusterSetup.COLOCATED: assert isinstance(dataset, DistDataset) assert isinstance(worker_options, MpDistSamplingWorkerOptions) - channel = BaseDistLoader.create_colocated_channel(worker_options) - # Compute degree tensors here, before the producer is constructed and - # before the staggered sleep in _init_colocated_connections. The - # all_reduce requires all ranks to participate simultaneously; deferring - # it to after the sleep would negate the stagger on worker spawning. - if isinstance(sampler_options, PPRSamplerOptions): - degree_tensors = dataset.degree_tensor - if isinstance(degree_tensors, dict): - logger.info( - f"Pre-computed degree tensors for PPR sampling across {len(degree_tensors)} edge types." - ) - else: - logger.info( - f"Pre-computed degree tensor for PPR sampling with {degree_tensors.size(0)} nodes." - ) - else: - degree_tensors = None producer: Union[ DistSamplingProducer, Callable[..., int] - ] = DistSamplingProducer( - data=dataset, + ] = BaseDistLoader.create_mp_producer( + dataset=dataset, sampler_input=sampler_input, sampling_config=sampling_config, worker_options=worker_options, - channel=channel, sampler_options=sampler_options, - degree_tensors=degree_tensors, ) else: producer = DistServer.create_sampling_producer diff --git a/gigl/distributed/distributed_neighborloader.py b/gigl/distributed/distributed_neighborloader.py index 2d3b82e9a..1cd12cdc9 100644 --- a/gigl/distributed/distributed_neighborloader.py +++ b/gigl/distributed/distributed_neighborloader.py @@ -267,33 +267,14 @@ def __init__( if self._sampling_cluster_setup == SamplingClusterSetup.COLOCATED: assert isinstance(dataset, DistDataset) assert isinstance(worker_options, MpDistSamplingWorkerOptions) - channel = BaseDistLoader.create_colocated_channel(worker_options) - # Compute degree tensors here, before the producer is constructed and - # before the staggered sleep in _init_colocated_connections. The - # all_reduce requires all ranks to participate simultaneously; deferring - # it to after the sleep would negate the stagger on worker spawning. - if isinstance(sampler_options, PPRSamplerOptions): - degree_tensors = dataset.degree_tensor - if isinstance(degree_tensors, dict): - logger.info( - f"Pre-computed degree tensors for PPR sampling across {len(degree_tensors)} edge types." - ) - else: - logger.info( - f"Pre-computed degree tensor for PPR sampling with {degree_tensors.size(0)} nodes." - ) - else: - degree_tensors = None producer: Union[ DistSamplingProducer, Callable[..., int] - ] = DistSamplingProducer( - data=dataset, + ] = BaseDistLoader.create_mp_producer( + dataset=dataset, sampler_input=input_data, sampling_config=sampling_config, worker_options=worker_options, - channel=channel, sampler_options=sampler_options, - degree_tensors=degree_tensors, ) else: producer = GiglDistServer.create_sampling_producer From 6e63172a3fe10155358d790710df4e3be964161c Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 1 Apr 2026 22:16:18 +0000 Subject: [PATCH 023/148] Update --- gigl/distributed/dist_ppr_sampler.py | 123 +++++++++++++++++++++------ gigl/distributed/sampler_options.py | 2 +- 2 files changed, 96 insertions(+), 29 deletions(-) diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 9e8c8a482..23c9d3c80 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -1,6 +1,5 @@ -# TODO (mkolodner-sc): Investigate whether concurrency for _sample_one_hop and _compute_ppr_scores will -# yield performance benefits. - +import asyncio +import time from collections import defaultdict from typing import Optional, Union @@ -24,6 +23,9 @@ # yield a bare EdgeType repr for ast.literal_eval). PPR_EDGE_INDEX_METADATA_KEY = "ppr_edge_index." PPR_WEIGHT_METADATA_KEY = "ppr_weight." +PPR_FETCH_TIME_MS_METADATA_KEY = "ppr_fetch_time_ms" +PPR_PUSH_TIME_MS_METADATA_KEY = "ppr_push_time_ms" +PPR_ITERATIONS_METADATA_KEY = "ppr_iterations" # Sentinel type names for homogeneous graphs. The PPR algorithm uses # dict[NodeType, ...] internally for both homo and hetero graphs; these @@ -292,18 +294,29 @@ async def _batch_fetch_neighbors( 5: (tensor([7]), tensor([0, 3]), tensor([2])), } """ - result: dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]] = {} - for eid, node_ids_tensor in nodes_by_etype_id.items(): - etype = self._etype_id_to_etype[eid] - # _sample_one_hop expects None for homogeneous graphs, not the PPR sentinel. - output: NeighborOutput = await self._sample_one_hop( - srcs=node_ids_tensor.to(device), - num_nbr=self._num_neighbors_per_hop, - etype=etype if etype != _PPR_HOMOGENEOUS_EDGE_TYPE else None, - ) - result[eid] = (node_ids_tensor, output.nbr, output.nbr_num) - - return result + # Fire all per-edge-type RPC calls concurrently. Each _sample_one_hop + # issues a single RPC round-trip; doing them in parallel rather than + # sequentially cuts fetch latency from O(num_edge_types) to O(1). + eids = list(nodes_by_etype_id.keys()) + outputs: list[NeighborOutput] = await asyncio.gather( + *[ + self._sample_one_hop( + srcs=nodes_by_etype_id[eid].to(device), + num_nbr=self._num_neighbors_per_hop, + # _sample_one_hop expects None for homogeneous graphs, not the PPR sentinel. + etype=( + self._etype_id_to_etype[eid] + if self._etype_id_to_etype[eid] != _PPR_HOMOGENEOUS_EDGE_TYPE + else None + ), + ) + for eid in eids + ] + ) + return { + eid: (nodes_by_etype_id[eid], output.nbr, output.nbr_num) + for eid, output in zip(eids, outputs) + } async def _compute_ppr_scores( self, @@ -313,6 +326,7 @@ async def _compute_ppr_scores( Union[torch.Tensor, dict[NodeType, torch.Tensor]], Union[torch.Tensor, dict[NodeType, torch.Tensor]], Union[torch.Tensor, dict[NodeType, torch.Tensor]], + tuple[float, float, int], ]: """ Compute PPR scores for seed nodes using the push-based approximation algorithm. @@ -354,6 +368,9 @@ async def _compute_ppr_scores( seed, shape ``[batch_size]``. Used to slice the flat tensors into per-seed groups: seed ``i``'s neighbors are at ``flat_neighbor_ids[sum(valid_counts[:i]) : sum(valid_counts[:i+1])]``. + - timing: ``(fetch_ms, push_ms, iterations)`` — wall-clock time + spent in neighbor fetch (ms), residual push (ms), and total loop + iteration count for this call. Example:: @@ -376,6 +393,10 @@ async def _compute_ppr_scores( self._degree_tensors_for_cpp, ) + total_fetch_ms = 0.0 + total_push_ms = 0.0 + total_iterations = 0 + while True: # drain_queue returns None when the queue is truly empty (convergence), # or a dict (possibly empty) when nodes were drained. An empty dict @@ -388,13 +409,18 @@ async def _compute_ppr_scores( nodes_by_etype_id: dict[int, torch.Tensor] = drain_result if nodes_by_etype_id: + fetch_start = time.perf_counter() fetched_by_etype_id = await self._batch_fetch_neighbors( nodes_by_etype_id, device ) + total_fetch_ms += (time.perf_counter() - fetch_start) * 1000 else: fetched_by_etype_id = {} + push_start = time.perf_counter() ppr_state.push_residuals(fetched_by_etype_id) + total_push_ms += (time.perf_counter() - push_start) * 1000 + total_iterations += 1 # Translate ntype_id integer keys back to NodeType strings for the rest # of the pipeline, and move tensors to the correct device. @@ -410,6 +436,7 @@ async def _compute_ppr_scores( ntype_to_flat_weights[ntype] = flat_weights.to(device) ntype_to_valid_counts[ntype] = valid_counts.to(device) + timing = (total_fetch_ms, total_push_ms, total_iterations) if self._is_homogeneous: assert ( len(ntype_to_flat_ids) == 1 @@ -419,9 +446,15 @@ async def _compute_ppr_scores( ntype_to_flat_ids[_PPR_HOMOGENEOUS_NODE_TYPE], ntype_to_flat_weights[_PPR_HOMOGENEOUS_NODE_TYPE], ntype_to_valid_counts[_PPR_HOMOGENEOUS_NODE_TYPE], + timing, ) else: - return ntype_to_flat_ids, ntype_to_flat_weights, ntype_to_valid_counts + return ( + ntype_to_flat_ids, + ntype_to_flat_weights, + ntype_to_valid_counts, + timing, + ) async def _sample_from_nodes( self, @@ -508,20 +541,42 @@ async def _sample_from_nodes( # NodeType -> global IDs (same values as nodes_to_sample). src_dict = inducer.init_node(nodes_to_sample) - # Compute PPR for each seed type, collecting flat global neighbor IDs, - # weights, and per-seed counts. Build nbr_dict for a single - # inducer.induce_next call using PPR edge types (seed_type, 'ppr', ntype) - # — the inducer only cares about etype[0] and etype[-1] as source/dest - # node types, so the relation name is arbitrary. + # Compute PPR for all seed types concurrently, collecting flat global + # neighbor IDs, weights, and per-seed counts. Build nbr_dict for a + # single inducer.induce_next call using PPR edge types + # (seed_type, 'ppr', ntype) — the inducer only cares about etype[0] + # and etype[-1] as source/dest node types, so the relation name is + # arbitrary. + # + # Each seed type's PPR computation is entirely independent: it creates + # its own PPRForwardPushState and only reads shared sampler attributes + # (degree tensors, edge-type maps) which are immutable after __init__. + # Running them with asyncio.gather allows their fetch phases to overlap, + # which is most beneficial when there are 2+ distinct seed node types + # (e.g. cross-type supervision edges like user→story). + seed_types = list(nodes_to_sample.keys()) + ppr_results = await asyncio.gather( + *[ + self._compute_ppr_scores(nodes_to_sample[seed_type], seed_type) + for seed_type in seed_types + ] + ) + nbr_dict: dict[EdgeType, list[torch.Tensor]] = {} ppr_edge_type_to_flat_weights: dict[EdgeType, torch.Tensor] = {} - - for seed_type, seed_nodes in nodes_to_sample.items(): - ( - ntype_to_flat_ids, - ntype_to_flat_weights, - ntype_to_valid_counts, - ) = await self._compute_ppr_scores(seed_nodes, seed_type) + total_fetch_ms = 0.0 + total_push_ms = 0.0 + total_iterations = 0 + + for seed_type, ( + ntype_to_flat_ids, + ntype_to_flat_weights, + ntype_to_valid_counts, + (fetch_ms, push_ms, iterations), + ) in zip(seed_types, ppr_results): + total_fetch_ms += fetch_ms + total_push_ms += push_ms + total_iterations += iterations assert isinstance(ntype_to_flat_ids, dict) assert isinstance(ntype_to_flat_weights, dict) assert isinstance(ntype_to_valid_counts, dict) @@ -583,6 +638,12 @@ async def _sample_from_nodes( metadata[f"{PPR_EDGE_INDEX_METADATA_KEY}{etype_str}"] = edge_index metadata[f"{PPR_WEIGHT_METADATA_KEY}{etype_str}"] = flat_weights + metadata[PPR_FETCH_TIME_MS_METADATA_KEY] = torch.tensor(total_fetch_ms) + metadata[PPR_PUSH_TIME_MS_METADATA_KEY] = torch.tensor(total_push_ms) + metadata[PPR_ITERATIONS_METADATA_KEY] = torch.tensor( + total_iterations, dtype=torch.long + ) + sample_output = HeteroSamplerOutput( node=node_dict, # row/col/edge are left empty rather than populated with PPR edges because @@ -613,6 +674,7 @@ async def _sample_from_nodes( homo_flat_ids, homo_flat_weights, homo_valid_counts, + (total_fetch_ms, total_push_ms, total_iterations), ) = await self._compute_ppr_scores(nodes_to_sample, None) assert isinstance(homo_flat_ids, torch.Tensor) assert isinstance(homo_flat_weights, torch.Tensor) @@ -634,6 +696,11 @@ async def _sample_from_nodes( metadata["edge_index"] = ppr_edge_index metadata["edge_attr"] = homo_flat_weights + metadata[PPR_FETCH_TIME_MS_METADATA_KEY] = torch.tensor(total_fetch_ms) + metadata[PPR_PUSH_TIME_MS_METADATA_KEY] = torch.tensor(total_push_ms) + metadata[PPR_ITERATIONS_METADATA_KEY] = torch.tensor( + total_iterations, dtype=torch.long + ) sample_output = SamplerOutput( node=all_nodes, diff --git a/gigl/distributed/sampler_options.py b/gigl/distributed/sampler_options.py index d87a83d52..eccdd70f7 100644 --- a/gigl/distributed/sampler_options.py +++ b/gigl/distributed/sampler_options.py @@ -64,7 +64,7 @@ class PPRSamplerOptions: alpha: float = 0.5 eps: float = 1e-4 max_ppr_nodes: int = 50 - num_neighbors_per_hop: int = 100_000 + num_neighbors_per_hop: int = 1_000 total_degree_dtype: torch.dtype = torch.int32 From 210c1ddc7be8d0e542d7a65cbab25a4c1690b90b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 1 Apr 2026 22:16:42 +0000 Subject: [PATCH 024/148] Upate --- containers/Dockerfile.src | 2 ++ gigl/scripts/post_install.py | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index b80295962..7b105084a 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -15,8 +15,10 @@ COPY uv.lock uv.lock COPY gigl/dep_vars.env gigl/dep_vars.env COPY deployment deployment COPY gigl gigl +COPY scripts scripts COPY snapchat snapchat COPY tests tests COPY examples examples RUN uv pip install -e . +RUN uv run python scripts/build_cpp_extensions.py build_ext --inplace diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index eed1528f6..d31b4244a 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -63,7 +63,12 @@ def main(): try: print("Building C++ extensions...") subprocess.run( - [sys.executable, "scripts/build_cpp_extensions.py", "build_ext", "--inplace"], + [ + sys.executable, + "scripts/build_cpp_extensions.py", + "build_ext", + "--inplace", + ], cwd=repo_root, check=True, ) From c16dd9d38300d30a542407d659df236644ac2d24 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 1 Apr 2026 23:30:23 +0000 Subject: [PATCH 025/148] Fix type check and remove unused etypes from num_sampled_edges --- gigl/distributed/utils/neighborloader.py | 1 + scripts/build_cpp_extensions.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gigl/distributed/utils/neighborloader.py b/gigl/distributed/utils/neighborloader.py index 974d12cf6..d0d96638f 100644 --- a/gigl/distributed/utils/neighborloader.py +++ b/gigl/distributed/utils/neighborloader.py @@ -189,6 +189,7 @@ def strip_non_ppr_edge_types( for edge_type in list(data.edge_types): if edge_type not in ppr_edge_types: del data[edge_type] + data.num_sampled_edges.pop(edge_type, None) return data diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index d05740860..f99e47f9b 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -10,13 +10,13 @@ from pathlib import Path -from setuptools import setup +from setuptools import Extension, setup from torch.utils.cpp_extension import BuildExtension, CppExtension _CSRC_DIR = Path("gigl/csrc") -def find_cpp_extensions() -> list[CppExtension]: +def find_cpp_extensions() -> list[Extension]: """Auto-discover pybind11 extension modules under ``gigl/csrc/``. Following PyTorch's csrc convention, only files named ``python_*.cpp`` are From d651f41f6f05028c5294ffdbb9d0d548056d3095 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 6 Apr 2026 23:29:52 +0000 Subject: [PATCH 026/148] fetched-count normalization, nodes_drained diagnostic, max_fetch_iterations, per-iteration timing metadata --- gigl/csrc/sampling/ppr_forward_push.cpp | 38 ++++- gigl/csrc/sampling/ppr_forward_push.h | 11 ++ gigl/csrc/sampling/ppr_forward_push.pyi | 1 + .../csrc/sampling/python_ppr_forward_push.cpp | 3 +- gigl/distributed/dist_ppr_sampler.py | 134 ++++++++++++++++-- gigl/distributed/dist_sampling_producer.py | 1 + gigl/distributed/sampler_options.py | 7 + 7 files changed, 175 insertions(+), 20 deletions(-) diff --git a/gigl/csrc/sampling/ppr_forward_push.cpp b/gigl/csrc/sampling/ppr_forward_push.cpp index a514907ab..1bbf05dbe 100644 --- a/gigl/csrc/sampling/ppr_forward_push.cpp +++ b/gigl/csrc/sampling/ppr_forward_push.cpp @@ -57,6 +57,7 @@ std::optional> PPRForwardPushState::d // in multiple seeds' queues: we only fetch each (node, etype) pair once. std::unordered_map> nodes_to_lookup; + int32_t total_drained_this_round = 0; for (int32_t s = 0; s < batch_size_; ++s) { for (int32_t nt = 0; nt < num_node_types_; ++nt) { if (queue_[s][nt].empty()) @@ -65,6 +66,7 @@ std::optional> PPRForwardPushState::d // Move the live queue into the snapshot (no data copy — O(1)). queued_nodes_[s][nt] = std::move(queue_[s][nt]); queue_[s][nt].clear(); + total_drained_this_round += static_cast(queued_nodes_[s][nt].size()); num_nodes_in_queue_ -= static_cast(queued_nodes_[s][nt].size()); for (int32_t node_id : queued_nodes_[s][nt]) { @@ -77,6 +79,8 @@ std::optional> PPRForwardPushState::d } } + nodes_drained_per_iteration_.push_back(total_drained_this_round); + std::unordered_map result; for (auto& [eid, node_set] : nodes_to_lookup) { std::vector ids(node_set.begin(), node_set.end()); @@ -85,6 +89,10 @@ std::optional> PPRForwardPushState::d return result; } +const std::vector& PPRForwardPushState::get_nodes_drained_per_iteration() const { + return nodes_drained_per_iteration_; +} + void PPRForwardPushState::push_residuals( const std::unordered_map>& fetched_by_etype_id) { @@ -135,13 +143,28 @@ void PPRForwardPushState::push_residuals( ppr_scores_[s][nt][src] += res; src_res[src] = 0.0; - int32_t total_deg = get_total_degree(src, nt); - // Destination-only nodes absorb residual but do not push further. - if (total_deg == 0) + // b. Count total fetched/cached neighbors across all edge types for + // this source node. We normalise by the number of neighbors we + // actually retrieved, not the true degree, so residual is fully + // distributed among known neighbors rather than leaking to unfetched + // ones (which matters when num_neighbors_per_hop < true_degree). + int32_t total_fetched = 0; + for (int32_t eid : node_type_to_edge_type_ids_[nt]) { + auto fi = fetched.find(pack_key(src, eid)); + if (fi != fetched.end()) { + total_fetched += static_cast(fi->second.size()); + } else { + auto ci = neighbor_cache_.find(pack_key(src, eid)); + if (ci != neighbor_cache_.end()) + total_fetched += static_cast(ci->second.size()); + } + } + // Destination-only nodes (or nodes with no fetched neighbors) absorb + // residual but do not push further. + if (total_fetched == 0) continue; - // b. Distribute: each neighbor receives an equal share. - double res_per_nbr = one_minus_alpha_ * res / static_cast(total_deg); + double res_per_nbr = one_minus_alpha_ * res / static_cast(total_fetched); for (int32_t eid : node_type_to_edge_type_ids_[nt]) { // Invariant: fetched and neighbor_cache_ are mutually exclusive for @@ -167,8 +190,9 @@ void PPRForwardPushState::push_residuals( for (int32_t nbr : *nbr_list) { residuals_[s][dst_nt][nbr] += res_per_nbr; - double threshold = requeue_threshold_factor_ * - static_cast(get_total_degree(nbr, dst_nt)); + double threshold = + requeue_threshold_factor_ * + static_cast(get_total_degree(nbr, dst_nt)); if (queue_[s][dst_nt].find(nbr) == queue_[s][dst_nt].end() && residuals_[s][dst_nt][nbr] >= threshold) { diff --git a/gigl/csrc/sampling/ppr_forward_push.h b/gigl/csrc/sampling/ppr_forward_push.h index 7f0c92f49..82973ff7a 100644 --- a/gigl/csrc/sampling/ppr_forward_push.h +++ b/gigl/csrc/sampling/ppr_forward_push.h @@ -118,4 +118,15 @@ class PPRForwardPushState { // Neighbor cache // ------------------------------------------------------------------------- std::unordered_map> neighbor_cache_; + + // ------------------------------------------------------------------------- + // Diagnostics (populated during the algorithm; read after convergence) + // ------------------------------------------------------------------------- + // Total nodes drained (across all seeds and node types) in each drain_queue() + // call. One entry per loop iteration; useful for understanding convergence speed. + std::vector nodes_drained_per_iteration_; + + public: + // Returns nodes_drained_per_iteration_ built up across all drain_queue() calls. + const std::vector& get_nodes_drained_per_iteration() const; }; diff --git a/gigl/csrc/sampling/ppr_forward_push.pyi b/gigl/csrc/sampling/ppr_forward_push.pyi index 265468c3c..9a3c78fea 100644 --- a/gigl/csrc/sampling/ppr_forward_push.pyi +++ b/gigl/csrc/sampling/ppr_forward_push.pyi @@ -19,3 +19,4 @@ class PPRForwardPushState: def extract_top_k( self, max_ppr_nodes: int ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: ... + def get_nodes_drained_per_iteration(self) -> list[int]: ... diff --git a/gigl/csrc/sampling/python_ppr_forward_push.cpp b/gigl/csrc/sampling/python_ppr_forward_push.cpp index ebf3fa27a..4a296abf8 100644 --- a/gigl/csrc/sampling/python_ppr_forward_push.cpp +++ b/gigl/csrc/sampling/python_ppr_forward_push.cpp @@ -59,5 +59,6 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { std::vector>()) .def("drain_queue", drain_queue_wrapper) .def("push_residuals", push_residuals_wrapper) - .def("extract_top_k", extract_top_k_wrapper); + .def("extract_top_k", extract_top_k_wrapper) + .def("get_nodes_drained_per_iteration", &PPRForwardPushState::get_nodes_drained_per_iteration); } diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 891b70772..b27786a31 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -13,10 +13,13 @@ from graphlearn_torch.typing import EdgeType, NodeType from graphlearn_torch.utils import merge_dict +from gigl.common.logger import Logger from gigl.csrc.sampling import PPRForwardPushState from gigl.distributed.base_sampler import BaseDistNeighborSampler from gigl.types.graph import is_label_edge_type +_logger = Logger() + # Trailing "." is an intentional separator. These constants are used both to # write metadata keys (f"{KEY}{repr(edge_type)}" → e.g. "ppr_edge_index.('user', 'to', 'story')") # and as the strip prefix in extract_edge_type_metadata (key[len(prefix):] must @@ -26,6 +29,10 @@ PPR_FETCH_TIME_MS_METADATA_KEY = "ppr_fetch_time_ms" PPR_PUSH_TIME_MS_METADATA_KEY = "ppr_push_time_ms" PPR_ITERATIONS_METADATA_KEY = "ppr_iterations" +PPR_NODES_PER_ITERATION_METADATA_KEY = "ppr_nodes_per_iteration" +PPR_FETCH_TIME_PER_ITER_MS_METADATA_KEY = "ppr_fetch_time_per_iter_ms" +PPR_PUSH_TIME_PER_ITER_MS_METADATA_KEY = "ppr_push_time_per_iter_ms" +PPR_NODES_NEEDING_FETCH_PER_ITER_METADATA_KEY = "ppr_nodes_needing_fetch_per_iter" # Sentinel type names for homogeneous graphs. The PPR algorithm uses # dict[NodeType, ...] internally for both homo and hetero graphs; these @@ -80,9 +87,10 @@ class DistPPRNeighborSampler(BaseDistNeighborSampler): but require more computation. Typical values: 1e-4 to 1e-6. max_ppr_nodes: Maximum number of nodes to return per seed based on PPR scores. num_neighbors_per_hop: Maximum number of neighbors to fetch per hop. - total_degree_dtype: Dtype for precomputed total-degree tensors. Defaults to - ``torch.int32``, which supports total degrees up to ~2 billion. Use a - larger dtype if nodes have exceptionally high aggregate degrees. + total_degree_dtype: Dtype for precomputed total-degree tensors. Defaults + to ``torch.int32``. Use a larger dtype if nodes have exceptionally high + aggregate degrees. + degree_tensors: Pre-computed degree tensors from the dataset. """ def __init__( @@ -94,6 +102,7 @@ def __init__( num_neighbors_per_hop: int = 100_000, total_degree_dtype: torch.dtype = torch.int32, degree_tensors: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], + max_fetch_iterations: int = 0, **kwargs, ): super().__init__(*args, **kwargs) @@ -102,6 +111,7 @@ def __init__( self._max_ppr_nodes = max_ppr_nodes self._requeue_threshold_factor = alpha * eps self._num_neighbors_per_hop = num_neighbors_per_hop + self._max_fetch_iterations = max_fetch_iterations # Build mapping from node type to edge types that can be traversed from that node type. self._node_type_to_edge_types: dict[NodeType, list[EdgeType]] = defaultdict( @@ -321,7 +331,7 @@ async def _compute_ppr_scores( Union[torch.Tensor, dict[NodeType, torch.Tensor]], Union[torch.Tensor, dict[NodeType, torch.Tensor]], Union[torch.Tensor, dict[NodeType, torch.Tensor]], - tuple[float, float, int], + tuple[float, float, int, list[int], list[float], list[float], list[int]], ]: """ Compute PPR scores for seed nodes using the push-based approximation algorithm. @@ -391,6 +401,10 @@ async def _compute_ppr_scores( total_fetch_ms = 0.0 total_push_ms = 0.0 total_iterations = 0 + fetch_iteration_count = 0 + fetch_ms_per_iter: list[float] = [] + push_ms_per_iter: list[float] = [] + nodes_needing_fetch_per_iter: list[int] = [] while True: # drain_queue returns None when the queue is truly empty (convergence), @@ -398,23 +412,41 @@ async def _compute_ppr_scores( # means all drained nodes either had cached neighbors or no outgoing # edges — we still call push_residuals to flush their residuals into # ppr_scores_. - drain_result: dict[int, torch.Tensor] | None = ppr_state.drain_queue() + drain_result: Optional[dict[int, torch.Tensor]] = ppr_state.drain_queue() if drain_result is None: break nodes_by_etype_id: dict[int, torch.Tensor] = drain_result - if nodes_by_etype_id: + fetch_budget_remaining = ( + self._max_fetch_iterations == 0 + or fetch_iteration_count < self._max_fetch_iterations + ) + if nodes_by_etype_id and fetch_budget_remaining: + # Total (node, edge_type) pairs needing RPCs this iteration. + # A node with uncached neighbors for k edge types contributes k here. + nodes_needing_fetch = sum(t.numel() for t in nodes_by_etype_id.values()) fetch_start = time.perf_counter() fetched_by_etype_id = await self._batch_fetch_neighbors( nodes_by_etype_id, device ) - total_fetch_ms += (time.perf_counter() - fetch_start) * 1000 + iter_fetch_ms = (time.perf_counter() - fetch_start) * 1000 + total_fetch_ms += iter_fetch_ms + fetch_iteration_count += 1 else: + # Either all nodes are cached, or the fetch budget is exhausted. + # push_residuals will propagate using the existing neighbor cache. + nodes_needing_fetch = 0 fetched_by_etype_id = {} + iter_fetch_ms = 0.0 + + nodes_needing_fetch_per_iter.append(nodes_needing_fetch) + fetch_ms_per_iter.append(iter_fetch_ms) push_start = time.perf_counter() ppr_state.push_residuals(fetched_by_etype_id) - total_push_ms += (time.perf_counter() - push_start) * 1000 + iter_push_ms = (time.perf_counter() - push_start) * 1000 + total_push_ms += iter_push_ms + push_ms_per_iter.append(iter_push_ms) total_iterations += 1 # Translate ntype_id integer keys back to NodeType strings for the rest @@ -431,7 +463,18 @@ async def _compute_ppr_scores( ntype_to_flat_weights[ntype] = flat_weights.to(device) ntype_to_valid_counts[ntype] = valid_counts.to(device) - timing = (total_fetch_ms, total_push_ms, total_iterations) + nodes_drained_per_iteration: list[ + int + ] = ppr_state.get_nodes_drained_per_iteration() + timing = ( + total_fetch_ms, + total_push_ms, + total_iterations, + nodes_drained_per_iteration, + fetch_ms_per_iter, + push_ms_per_iter, + nodes_needing_fetch_per_iter, + ) if self._is_homogeneous: assert ( len(ntype_to_flat_ids) == 1 @@ -562,16 +605,48 @@ async def _sample_from_nodes( total_fetch_ms = 0.0 total_push_ms = 0.0 total_iterations = 0 + total_nodes_per_iteration: list[int] = [] + total_fetch_ms_per_iter: list[float] = [] + total_push_ms_per_iter: list[float] = [] + total_nodes_needing_fetch_per_iter: list[int] = [] for seed_type, ( ntype_to_flat_ids, ntype_to_flat_weights, ntype_to_valid_counts, - (fetch_ms, push_ms, iterations), + ( + fetch_ms, + push_ms, + iterations, + nodes_per_iter, + fetch_ms_per_iter, + push_ms_per_iter, + nodes_needing_fetch_per_iter, + ), ) in zip(seed_types, ppr_results): total_fetch_ms += fetch_ms total_push_ms += push_ms total_iterations += iterations + for i, count in enumerate(nodes_per_iter): + if i < len(total_nodes_per_iteration): + total_nodes_per_iteration[i] += count + else: + total_nodes_per_iteration.append(count) + for i, val in enumerate(fetch_ms_per_iter): + if i < len(total_fetch_ms_per_iter): + total_fetch_ms_per_iter[i] += val + else: + total_fetch_ms_per_iter.append(val) + for i, val in enumerate(push_ms_per_iter): + if i < len(total_push_ms_per_iter): + total_push_ms_per_iter[i] += val + else: + total_push_ms_per_iter.append(val) + for i, val in enumerate(nodes_needing_fetch_per_iter): + if i < len(total_nodes_needing_fetch_per_iter): + total_nodes_needing_fetch_per_iter[i] += val + else: + total_nodes_needing_fetch_per_iter.append(val) assert isinstance(ntype_to_flat_ids, dict) assert isinstance(ntype_to_flat_weights, dict) assert isinstance(ntype_to_valid_counts, dict) @@ -621,7 +696,10 @@ async def _sample_from_nodes( # rows_dict and cols_dict are keyed by PPR edge type and give # flat local source/destination indices respectively, aligned with # the flat_ids order passed to induce_next. - for ppr_edge_type, flat_weights in ppr_edge_type_to_flat_weights.items(): + for ( + ppr_edge_type, + flat_weights, + ) in ppr_edge_type_to_flat_weights.items(): rows = rows_dict.get(ppr_edge_type) cols = cols_dict.get(ppr_edge_type) if rows is not None and cols is not None: @@ -638,6 +716,18 @@ async def _sample_from_nodes( metadata[PPR_ITERATIONS_METADATA_KEY] = torch.tensor( total_iterations, dtype=torch.long ) + metadata[PPR_NODES_PER_ITERATION_METADATA_KEY] = torch.tensor( + total_nodes_per_iteration, dtype=torch.long + ) + metadata[PPR_FETCH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( + total_fetch_ms_per_iter, dtype=torch.float + ) + metadata[PPR_PUSH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( + total_push_ms_per_iter, dtype=torch.float + ) + metadata[PPR_NODES_NEEDING_FETCH_PER_ITER_METADATA_KEY] = torch.tensor( + total_nodes_needing_fetch_per_iter, dtype=torch.long + ) sample_output = HeteroSamplerOutput( node=node_dict, @@ -669,7 +759,15 @@ async def _sample_from_nodes( homo_flat_ids, homo_flat_weights, homo_valid_counts, - (total_fetch_ms, total_push_ms, total_iterations), + ( + total_fetch_ms, + total_push_ms, + total_iterations, + total_nodes_per_iteration, + total_fetch_ms_per_iter, + total_push_ms_per_iter, + total_nodes_needing_fetch_per_iter, + ), ) = await self._compute_ppr_scores(nodes_to_sample, None) assert isinstance(homo_flat_ids, torch.Tensor) assert isinstance(homo_flat_weights, torch.Tensor) @@ -696,6 +794,18 @@ async def _sample_from_nodes( metadata[PPR_ITERATIONS_METADATA_KEY] = torch.tensor( total_iterations, dtype=torch.long ) + metadata[PPR_NODES_PER_ITERATION_METADATA_KEY] = torch.tensor( + total_nodes_per_iteration, dtype=torch.long + ) + metadata[PPR_FETCH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( + total_fetch_ms_per_iter, dtype=torch.float + ) + metadata[PPR_PUSH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( + total_push_ms_per_iter, dtype=torch.float + ) + metadata[PPR_NODES_NEEDING_FETCH_PER_ITER_METADATA_KEY] = torch.tensor( + total_nodes_needing_fetch_per_iter, dtype=torch.long + ) sample_output = SamplerOutput( node=all_nodes, diff --git a/gigl/distributed/dist_sampling_producer.py b/gigl/distributed/dist_sampling_producer.py index f155bd929..490514c6c 100644 --- a/gigl/distributed/dist_sampling_producer.py +++ b/gigl/distributed/dist_sampling_producer.py @@ -131,6 +131,7 @@ def _sampling_worker_loop( num_neighbors_per_hop=sampler_options.num_neighbors_per_hop, total_degree_dtype=sampler_options.total_degree_dtype, degree_tensors=degree_tensors, + max_fetch_iterations=sampler_options.max_fetch_iterations, ) else: raise NotImplementedError( diff --git a/gigl/distributed/sampler_options.py b/gigl/distributed/sampler_options.py index 639a932a5..d72c9092e 100644 --- a/gigl/distributed/sampler_options.py +++ b/gigl/distributed/sampler_options.py @@ -59,6 +59,12 @@ class PPRSamplerOptions: total_degree_dtype: Dtype for precomputed total-degree tensors. Defaults to ``torch.int32``, which supports total degrees up to ~2 billion. Use a larger dtype if nodes have exceptionally high aggregate degrees. + max_fetch_iterations: Maximum number of iterations that issue RPC neighbor + fetches. After this many fetch iterations, subsequent iterations push + residuals using only already-cached neighbor lists (no new RPCs). + The algorithm still runs to convergence — re-enqueued nodes propagate + through cached neighbors at negligible cost. Set to 0 (default) for + no fetch limit. """ alpha: float = 0.5 @@ -66,6 +72,7 @@ class PPRSamplerOptions: max_ppr_nodes: int = 50 num_neighbors_per_hop: int = 1_000 total_degree_dtype: torch.dtype = torch.int32 + max_fetch_iterations: int = 0 SamplerOptions = Union[KHopNeighborSamplerOptions, PPRSamplerOptions] From 35e52bcda2527b34bb7ffb885e13585a6193ec8d Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 18:00:52 +0000 Subject: [PATCH 027/148] Add event loop threading --- gigl/csrc/sampling/python_ppr_forward_push.cpp | 9 ++++++++- gigl/distributed/dist_ppr_sampler.py | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/gigl/csrc/sampling/python_ppr_forward_push.cpp b/gigl/csrc/sampling/python_ppr_forward_push.cpp index 4a296abf8..78de24cbc 100644 --- a/gigl/csrc/sampling/python_ppr_forward_push.cpp +++ b/gigl/csrc/sampling/python_ppr_forward_push.cpp @@ -29,13 +29,20 @@ static py::object drain_queue_wrapper(PPRForwardPushState& self) { // Convert to C++ map before delegating. static void push_residuals_wrapper(PPRForwardPushState& self, py::dict fetched_by_etype_id) { std::unordered_map> cpp_map; + // Dict iteration touches Python objects — GIL must be held here. for (auto item : fetched_by_etype_id) { int32_t eid = item.first.cast(); auto tup = item.second.cast(); cpp_map[eid] = {tup[0].cast(), tup[1].cast(), tup[2].cast()}; } - self.push_residuals(cpp_map); + // C++ push only uses tensor accessor/data_ptr APIs — GIL-safe to release. + // Releasing here lets the asyncio event loop process RPC completion callbacks + // from other concurrent PPR coroutines while this push runs. + { + py::gil_scoped_release release; + self.push_residuals(cpp_map); + } } // extract_top_k: C++ returns map>. diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index b27786a31..dfb9220d2 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -443,7 +443,9 @@ async def _compute_ppr_scores( fetch_ms_per_iter.append(iter_fetch_ms) push_start = time.perf_counter() - ppr_state.push_residuals(fetched_by_etype_id) + await asyncio.get_running_loop().run_in_executor( + None, ppr_state.push_residuals, fetched_by_etype_id + ) iter_push_ms = (time.perf_counter() - push_start) * 1000 total_push_ms += iter_push_ms push_ms_per_iter.append(iter_push_ms) From 628a9f2bc87252bfa2098292635119a380263355 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 18:41:21 +0000 Subject: [PATCH 028/148] Update tidy and format --- .clang-format | 110 +++++++++++---- .clang-tidy | 236 ++++++++++++++++++++++++++++---- docs/cpp_style_guide.md | 156 +++++++++++++++++++++ mypy.ini | 3 + scripts/build_cpp_extensions.py | 3 +- 5 files changed, 452 insertions(+), 56 deletions(-) create mode 100644 docs/cpp_style_guide.md diff --git a/.clang-format b/.clang-format index f702e9dce..e623d7ac7 100644 --- a/.clang-format +++ b/.clang-format @@ -1,31 +1,83 @@ -# clang-format configuration for GiGL C++ sources. -# Run: clang-format -i (format in-place) -# clang-format --dry-run --Werror (check only) -BasedOnStyle: Google - -# Match the 100-column limit used for Python throughout the codebase. -ColumnLimit: 100 - -# 4-space indentation (Google style defaults to 2; override to match existing code). -IndentWidth: 4 -ContinuationIndentWidth: 4 - -# Align consecutive = signs in variable declarations for readability. -AlignConsecutiveAssignments: - Enabled: true - AcrossEmptyLines: false - AcrossComments: false - -# Keep short functions on one line only when they are truly trivial (getters/setters). -AllowShortFunctionsOnASingleLine: Inline - -# Never put if/else/loop bodies on the same line as the condition. -AllowShortIfStatementsOnASingleLine: Never +--- +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false - -# Always break before the opening brace of a namespace, class, or function body. +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BreakAfterJavaFieldAnnotations: false +BreakBeforeBinaryOperators: None BreakBeforeBraces: Attach - -# Sort #include blocks: standard library first, then project headers. -SortIncludes: CaseSensitive -IncludeBlocks: Regroup +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '$' +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 10000000 +PointerAlignment: Left +RawStringFormats: + - Delimiters: [pb] + Language: TextProto + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy index fe02e7100..a0e6e57d3 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,29 +1,213 @@ -# clang-tidy configuration for GiGL C++ sources. -# Run: clang-tidy -p build/compile_commands.json -# -# Checks are opt-in by prefix. Each line below enables (*) or disables (-) -# a category. More specific patterns override broader ones. - +--- Checks: > - clang-analyzer-*, - bugprone-use-after-move, - bugprone-incorrect-roundings, - bugprone-integer-division, - bugprone-signed-char-misuse, - bugprone-suspicious-memset-usage, - modernize-use-nullptr, - modernize-loop-convert, - modernize-use-override, - performance-unnecessary-value-param, - performance-unnecessary-copy-initialization, - readability-const-return-type, + boost-use-to-string, + bugprone-*, -bugprone-easily-swappable-parameters, - -clang-analyzer-optin.cplusplus.UninitializedObject, - -modernize-use-trailing-return-type - -# Treat every enabled warning as an error so the build fails loudly. -WarningsAsErrors: "*" + -bugprone-narrowing-conversions, + cert-err34-c, + cert-flp30-c, + cert-msc32-c, + cert-msc50-cpp, + cert-msc51-cpp, + clang-analyzer-*, + -clang-analyzer-alpha*, + -clang-analyzer-cplusplus.NewDeleteLeaks, + -clang-analyzer-osx*, + clang-diagnostic-*, + cppcoreguidelines-interfaces-global-init, + cppcoreguidelines-no-malloc, + cppcoreguidelines-pro-type-static-cast-downcast, + cppcoreguidelines-pro-type-union-access, + cppcoreguidelines-slicing, + google-build-namespaces, + google-explicit-constructor, + google-global-names-in-headers, + google-readability-casting, + google-runtime-member-string-references, + google-runtime-memset, + hicpp-exception-baseclass, + misc-*, + -misc-no-recursion, + modernize-*, + -modernize-avoid-c-arrays, + performance-*, + readability-*, + -readability-identifier-length, + -readability-magic-numbers, -# Only apply header-file checks to GiGL-owned headers, not third-party -# (torch, pybind11) headers pulled in by includes. -HeaderFilterRegex: "gigl/.*" +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' +FormatStyle: none +User: jenkins +CheckOptions: + - key: bugprone-argument-comment.StrictMode + value: '0' + - key: bugprone-assert-side-effect.AssertMacros + value: 'assert,SC_ASSERT' + - key: bugprone-assert-side-effect.CheckFunctionCalls + value: '0' + - key: bugprone-dangling-handle.HandleClasses + value: 'std::basic_string_view;std::experimental::basic_string_view' + - key: bugprone-string-constructor.LargeLengthThreshold + value: '8388608' + - key: bugprone-string-constructor.WarnOnLargeLength + value: '1' + - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays + value: '1' + - key: google-global-names-in-headers.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: misc-definitions-in-headers.HeaderFileExtensions + value: ',h,hh,hpp,hxx' + - key: misc-definitions-in-headers.UseHeaderFileExtension + value: '1' + - key: misc-misplaced-widening-cast.CheckImplicitCasts + value: '0' + - key: misc-sizeof-expression.WarnOnSizeOfCompareToConstant + value: '1' + - key: misc-sizeof-expression.WarnOnSizeOfConstant + value: '1' + - key: misc-sizeof-expression.WarnOnSizeOfThis + value: '1' + - key: misc-suspicious-enum-usage.StrictMode + value: '0' + - key: misc-suspicious-missing-comma.MaxConcatenatedTokens + value: '5' + - key: misc-suspicious-missing-comma.RatioThreshold + value: '0.200000' + - key: misc-suspicious-missing-comma.SizeThreshold + value: '5' + - key: misc-suspicious-string-compare.StringCompareLikeFunctions + value: '' + - key: misc-suspicious-string-compare.WarnOnImplicitComparison + value: '1' + - key: misc-suspicious-string-compare.WarnOnLogicalNotComparison + value: '0' + - key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries + value: '1' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-loop-convert.UseCxx20ReverseRanges + value: '0' + - key: modernize-make-unique.IgnoreMacros + value: '1' + - key: modernize-make-unique.IncludeStyle + value: 'llvm' + - key: modernize-make-unique.MakeSmartPtrFunction + value: 'std::make_unique' + - key: modernize-make-unique.MakeSmartPtrFunctionHeader + value: memory + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-emplace.ContainersWithPushBack + value: '::std::vector;::std::list;::std::deque' + - key: modernize-use-emplace.SmartPointers + value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' + - key: modernize-use-emplace.TupleMakeFunctions + value: '::std::make_pair;::std::make_tuple' + - key: modernize-use-emplace.TupleTypes + value: '::std::pair;::std::tuple' + - key: modernize-use-noexcept.ReplacementString + value: '' + - key: modernize-use-noexcept.UseNoexceptFalse + value: '1' + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: modernize-use-transparent-functors.SafeMode + value: '0' + - key: performance-faster-string-find.StringLikeClasses + value: 'std::basic_string' + - key: performance-for-range-copy.WarnOnAllAutoCopies + value: '0' + - key: performance-inefficient-string-concatenation.StrictMode + value: '0' + - key: performance-inefficient-vector-operation.VectorLikeClasses + value: '::std::vector' + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: '1' + - key: performance-move-constructor-init.IncludeStyle + value: llvm + - key: performance-type-promotion-in-math-fn.IncludeStyle + value: llvm + - key: readability-braces-around-statements.ShortStatementLines + value: '2' + - key: readability-function-size.BranchThreshold + value: '4294967295' + - key: readability-function-size.LineThreshold + value: '1000' + - key: readability-function-size.NestingThreshold + value: '4294967295' + - key: readability-function-size.ParameterThreshold + value: '4294967295' + - key: readability-function-size.StatementThreshold + value: '800' + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.ClassConstantPrefix + value: k + - key: readability-identifier-naming.ClassConstantCase + value: CamelCase + - key: readability-identifier-naming.ClassMemberCase + value: camelBack + - key: readability-identifier-naming.ConstexprVariableCase + value: CamelCase + - key: readability-identifier-naming.ConstexprVariablePrefix + value: k + - key: readability-identifier-naming.EnumCase + value: CamelCase + - key: readability-identifier-naming.EnumConstantCase + value: CamelCase + - key: readability-identifier-naming.FunctionCase + value: camelBack + - key: readability-identifier-naming.GlobalConstantPrefix + value: k + - key: readability-identifier-naming.GlobalConstantCase + value: CamelCase + - key: readability-identifier-naming.IgnoreFailedSplit + value: '0' + - key: readability-identifier-naming.LocalConstantCase + value: camelBack + - key: readability-identifier-naming.MemberCase + value: camelBack + - key: readability-identifier-naming.MethodCase + value: camelBack + - key: readability-identifier-naming.ParameterCase + value: camelBack + - key: readability-identifier-naming.PrivateMemberCase + value: camelBack + - key: readability-identifier-naming.PrivateMemberPrefix + value: _ + - key: readability-identifier-naming.ProtectedMemberCase + value: camelBack + - key: readability-identifier-naming.ProtectedMemberPrefix + value: _ + - key: readability-identifier-naming.PublicMemberCase + value: camelBack + - key: readability-identifier-naming.TemplateParameterCase + value: camelBack + - key: readability-identifier-naming.TypeTemplateParameterCase + value: CamelCase + - key: readability-identifier-naming.UnionCase + value: CamelCase + - key: readability-identifier-naming.VariableCase + value: camelBack + - key: readability-implicit-bool-conversion.AllowPointerConditions + value: '1' + - key: readability-simplify-boolean-expr.ChainedConditionalAssignment + value: '0' + - key: readability-simplify-boolean-expr.ChainedConditionalReturn + value: '0' + - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold + value: '3' +... diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md new file mode 100644 index 000000000..bb6bd960e --- /dev/null +++ b/docs/cpp_style_guide.md @@ -0,0 +1,156 @@ +# C++ Style Guide + +GiGL enforces C++ style automatically via two tools: + +- **clang-format** (`.clang-format`) — code formatting +- **clang-tidy** (`.clang-tidy`) — static analysis and lint + +Both run as part of CI. All clang-tidy warnings are treated as errors. + +## Running the Tools + +```bash +# Format all C++ files in-place +clang-format -i $(find gigl/csrc -name '*.cpp' -o -name '*.h') + +# Run static analysis +clang-tidy gigl/csrc/**/*.cpp +``` + +--- + +## Formatting (`.clang-format`) + +The style is based on LLVM with the following notable deviations: + +### Line length + +``` +ColumnLimit: 120 +``` + +120 columns rather than the LLVM default of 80. ML and graph code tends to have +longer identifiers and nested template types; 120 gives enough room without +forcing awkward wraps. + +### Indentation and braces + +``` +IndentWidth: 4 +BreakBeforeBraces: Attach # K&R / "same-line" style +UseTab: Never +IndentCaseLabels: true # case labels indented inside switch +NamespaceIndentation: None # namespace bodies not indented +``` + +### Pointer and reference alignment + +``` +PointerAlignment: Left +``` + +Pointers bind to the type, not the name: `int* x`, not `int *x`. + +### Parameter and argument wrapping + +``` +BinPackArguments: false +BinPackParameters: false +``` + +When a function call or declaration doesn't fit on one line, every argument/parameter +gets its own line. Mixed "bin-packing" (some on one line, some wrapped) is +not allowed. + +### Templates + +``` +AlwaysBreakTemplateDeclarations: true +``` + +`template <...>` always appears on its own line, keeping the declaration +signature visually separate from the template header. + +### Include ordering + +Includes are sorted and split into three priority groups: + +| Priority | Pattern | Group | +|----------|---------|-------| +| 1 | `.*` | Local project headers (first) | +| 2 | `^"(llvm\|llvm-c\|clang\|clang-c)/"` | LLVM/Clang internal headers | +| 3 | `^(<\|"(gtest\|isl\|json)/)` | System and third-party headers (last) | + +### Raw string formatting + +Raw string literals with the `pb` delimiter (e.g. `R"pb(...)pb"`) are +formatted as TextProto using Google style, matching the protobuf idiom used +throughout the codebase. + +--- + +## Static Analysis (`.clang-tidy`) + +### Check philosophy + +A broad set of check families is enabled to catch bugs, enforce modern C++ +idioms, and maintain readability. All warnings are errors — there is no +"warning-only" category. + +Enabled families: + +| Family | What it covers | +|--------|---------------| +| `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | +| `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | +| `cert-*` (selected) | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | +| `clang-analyzer-*` | Clang static analyzer: memory safety, null dereferences, use-after-free, etc. | +| `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks | +| `cppcoreguidelines-*` (selected) | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | +| `google-*` (selected) | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | +| `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | +| `misc-*` | Miscellaneous: header-only definitions, suspicious enum usage, throw-by-value/catch-by-reference, etc. | +| `modernize-*` | Modernize to C++11/14/17: `nullptr`, range-based for, `make_unique`, `using` aliases, etc. | +| `performance-*` | Unnecessary copies, inefficient string ops, missed `emplace`, type promotions in math functions | +| `readability-*` | Naming conventions, braces around statements, boolean simplification, function size limits | + +### Disabled checks + +Some checks in the above families are disabled where they produce excessive +noise or conflict with common patterns in this codebase: + +| Disabled check | Reason | +|---------------|--------| +| `bugprone-easily-swappable-parameters` | Tensor and sampler APIs legitimately have many adjacent same-typed parameters | +| `bugprone-narrowing-conversions` | Too noisy in ML code mixing `int`/`int64_t`/`size_t` for tensor dimensions | +| `clang-analyzer-alpha*` | Alpha checks are experimental and unstable | +| `clang-analyzer-cplusplus.NewDeleteLeaks` | Ownership is managed via smart pointers; raw-new leaks are already caught elsewhere | +| `misc-no-recursion` | Recursive graph algorithms are intentional | +| `modernize-avoid-c-arrays` | C arrays are needed for pybind11 and C-interop code | +| `readability-identifier-length` | Short loop variables (`i`, `j`, `k`) are idiomatic | +| `readability-magic-numbers` | Literal constants are common in ML code (e.g. feature dimensions) | + +### Naming conventions + +Enforced via `readability-identifier-naming`: + +| Identifier kind | Convention | Example | +|----------------|-----------|---------| +| Classes, enums, unions | `CamelCase` | `DistDataset` | +| Type template parameters | `CamelCase` | `NodeType` | +| Functions, methods | `camelBack` | `sampleNeighbors` | +| Variables, parameters, members | `camelBack` | `numNodes` | +| Private/protected members | `camelBack` with `_` prefix | `_nodeFeatures` | +| Constants (`constexpr`, `const` globals, class constants) | `CamelCase` with `k` prefix | `kMaxBatchSize` | + +### Key option tuning + +| Option | Value | Effect | +|--------|-------|--------| +| `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | +| `HeaderFilterRegex` | `.*` | Checks apply to all headers, not just implementation files | +| `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | +| `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | +| `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | +| `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | +| `readability-braces-around-statements.ShortStatementLines` | `2` | Single-line bodies up to 2 lines may omit braces | diff --git a/mypy.ini b/mypy.ini index d488c2a83..b034f60d4 100644 --- a/mypy.ini +++ b/mypy.ini @@ -16,6 +16,9 @@ ignore_missing_imports = True [mypy-setuptools] ignore_missing_imports = True +[mypy-setuptools.extension] +ignore_missing_imports = True + [mypy-tensorflow_data_validation] ignore_missing_imports = True diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index d05740860..5bc3dd8bf 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -11,12 +11,13 @@ from pathlib import Path from setuptools import setup +from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension _CSRC_DIR = Path("gigl/csrc") -def find_cpp_extensions() -> list[CppExtension]: +def find_cpp_extensions() -> list[Extension]: """Auto-discover pybind11 extension modules under ``gigl/csrc/``. Following PyTorch's csrc convention, only files named ``python_*.cpp`` are From 75863a61d872a423e797879b9b7cd8b091428673 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 20:36:22 +0000 Subject: [PATCH 029/148] Update --- .clang-tidy | 1 + Makefile | 2 +- docs/cpp_style_guide.md | 123 ++++++++++++++++++++-------------------- 3 files changed, 62 insertions(+), 64 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index a0e6e57d3..279b7f030 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -32,6 +32,7 @@ Checks: > -modernize-avoid-c-arrays, performance-*, readability-*, + -readability-container-contains, -readability-identifier-length, -readability-magic-numbers, diff --git a/Makefile b/Makefile index 89416cfa7..28bbd3d18 100644 --- a/Makefile +++ b/Makefile @@ -156,7 +156,7 @@ format_md: format_cpp: $(if $(CPP_SOURCES), clang-format -i --style=file $(CPP_SOURCES)) -format: format_py format_scala format_md format_cpp +format: format_py format_cpp format_scala format_md type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index bb6bd960e..4aa0c30c1 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -17,7 +17,7 @@ clang-format -i $(find gigl/csrc -name '*.cpp' -o -name '*.h') clang-tidy gigl/csrc/**/*.cpp ``` ---- +______________________________________________________________________ ## Formatting (`.clang-format`) @@ -29,9 +29,8 @@ The style is based on LLVM with the following notable deviations: ColumnLimit: 120 ``` -120 columns rather than the LLVM default of 80. ML and graph code tends to have -longer identifiers and nested template types; 120 gives enough room without -forcing awkward wraps. +120 columns rather than the LLVM default of 80. ML and graph code tends to have longer identifiers and nested template +types; 120 gives enough room without forcing awkward wraps. ### Indentation and braces @@ -58,9 +57,8 @@ BinPackArguments: false BinPackParameters: false ``` -When a function call or declaration doesn't fit on one line, every argument/parameter -gets its own line. Mixed "bin-packing" (some on one line, some wrapped) is -not allowed. +When a function call or declaration doesn't fit on one line, every argument/parameter gets its own line. Mixed +"bin-packing" (some on one line, some wrapped) is not allowed. ### Templates @@ -68,89 +66,88 @@ not allowed. AlwaysBreakTemplateDeclarations: true ``` -`template <...>` always appears on its own line, keeping the declaration -signature visually separate from the template header. +`template <...>` always appears on its own line, keeping the declaration signature visually separate from the template +header. ### Include ordering Includes are sorted and split into three priority groups: -| Priority | Pattern | Group | -|----------|---------|-------| -| 1 | `.*` | Local project headers (first) | -| 2 | `^"(llvm\|llvm-c\|clang\|clang-c)/"` | LLVM/Clang internal headers | -| 3 | `^(<\|"(gtest\|isl\|json)/)` | System and third-party headers (last) | +| Priority | Pattern | Group | +| -------- | ------------------------------------ | ------------------------------------- | +| 1 | `.*` | Local project headers (first) | +| 2 | `^"(llvm\|llvm-c\|clang\|clang-c)/"` | LLVM/Clang internal headers | +| 3 | `^(<\|"(gtest\|isl\|json)/)` | System and third-party headers (last) | ### Raw string formatting -Raw string literals with the `pb` delimiter (e.g. `R"pb(...)pb"`) are -formatted as TextProto using Google style, matching the protobuf idiom used -throughout the codebase. +Raw string literals with the `pb` delimiter (e.g. `R"pb(...)pb"`) are formatted as TextProto using Google style, +matching the protobuf idiom used throughout the codebase. ---- +______________________________________________________________________ ## Static Analysis (`.clang-tidy`) ### Check philosophy -A broad set of check families is enabled to catch bugs, enforce modern C++ -idioms, and maintain readability. All warnings are errors — there is no -"warning-only" category. +A broad set of check families is enabled to catch bugs, enforce modern C++ idioms, and maintain readability. All +warnings are errors — there is no "warning-only" category. Enabled families: -| Family | What it covers | -|--------|---------------| -| `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | -| `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | -| `cert-*` (selected) | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | -| `clang-analyzer-*` | Clang static analyzer: memory safety, null dereferences, use-after-free, etc. | -| `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks | -| `cppcoreguidelines-*` (selected) | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | -| `google-*` (selected) | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | -| `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | -| `misc-*` | Miscellaneous: header-only definitions, suspicious enum usage, throw-by-value/catch-by-reference, etc. | -| `modernize-*` | Modernize to C++11/14/17: `nullptr`, range-based for, `make_unique`, `using` aliases, etc. | -| `performance-*` | Unnecessary copies, inefficient string ops, missed `emplace`, type promotions in math functions | -| `readability-*` | Naming conventions, braces around statements, boolean simplification, function size limits | +| Family | What it covers | +| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | +| `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | +| `cert-*` (selected) | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | +| `clang-analyzer-*` | Clang static analyzer: memory safety, null dereferences, use-after-free, etc. | +| `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks | +| `cppcoreguidelines-*` (selected) | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | +| `google-*` (selected) | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | +| `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | +| `misc-*` | Miscellaneous: header-only definitions, suspicious enum usage, throw-by-value/catch-by-reference, etc. | +| `modernize-*` | Modernize to C++11/14/17: `nullptr`, range-based for, `make_unique`, `using` aliases, etc. | +| `performance-*` | Unnecessary copies, inefficient string ops, missed `emplace`, type promotions in math functions | +| `readability-*` | Naming conventions, braces around statements, boolean simplification, function size limits | ### Disabled checks -Some checks in the above families are disabled where they produce excessive -noise or conflict with common patterns in this codebase: +Some checks in the above families are disabled where they produce excessive noise or conflict with common patterns in +this codebase: -| Disabled check | Reason | -|---------------|--------| -| `bugprone-easily-swappable-parameters` | Tensor and sampler APIs legitimately have many adjacent same-typed parameters | -| `bugprone-narrowing-conversions` | Too noisy in ML code mixing `int`/`int64_t`/`size_t` for tensor dimensions | -| `clang-analyzer-alpha*` | Alpha checks are experimental and unstable | +| Disabled check | Reason | +| ----------------------------------------- | ----------------------------------------------------------------------------------- | +| `bugprone-easily-swappable-parameters` | Tensor and sampler APIs legitimately have many adjacent same-typed parameters | +| `bugprone-narrowing-conversions` | Too noisy in ML code mixing `int`/`int64_t`/`size_t` for tensor dimensions | +| `clang-analyzer-alpha*` | Alpha checks are experimental and unstable | | `clang-analyzer-cplusplus.NewDeleteLeaks` | Ownership is managed via smart pointers; raw-new leaks are already caught elsewhere | -| `misc-no-recursion` | Recursive graph algorithms are intentional | -| `modernize-avoid-c-arrays` | C arrays are needed for pybind11 and C-interop code | -| `readability-identifier-length` | Short loop variables (`i`, `j`, `k`) are idiomatic | -| `readability-magic-numbers` | Literal constants are common in ML code (e.g. feature dimensions) | +| `misc-no-recursion` | Recursive graph algorithms are intentional | +| `modernize-avoid-c-arrays` | C arrays are needed for pybind11 and C-interop code | +| `readability-container-contains` | `.contains()` requires C++20; the codebase builds with C++17 | +| `readability-identifier-length` | Short loop variables (`i`, `j`, `k`) are idiomatic | +| `readability-magic-numbers` | Literal constants are common in ML code (e.g. feature dimensions) | ### Naming conventions Enforced via `readability-identifier-naming`: -| Identifier kind | Convention | Example | -|----------------|-----------|---------| -| Classes, enums, unions | `CamelCase` | `DistDataset` | -| Type template parameters | `CamelCase` | `NodeType` | -| Functions, methods | `camelBack` | `sampleNeighbors` | -| Variables, parameters, members | `camelBack` | `numNodes` | -| Private/protected members | `camelBack` with `_` prefix | `_nodeFeatures` | -| Constants (`constexpr`, `const` globals, class constants) | `CamelCase` with `k` prefix | `kMaxBatchSize` | +| Identifier kind | Convention | Example | +| --------------------------------------------------------- | --------------------------- | ----------------- | +| Classes, enums, unions | `CamelCase` | `DistDataset` | +| Type template parameters | `CamelCase` | `NodeType` | +| Functions, methods | `camelBack` | `sampleNeighbors` | +| Variables, parameters, members | `camelBack` | `numNodes` | +| Private/protected members | `camelBack` with `_` prefix | `_nodeFeatures` | +| Constants (`constexpr`, `const` globals, class constants) | `CamelCase` with `k` prefix | `kMaxBatchSize` | ### Key option tuning -| Option | Value | Effect | -|--------|-------|--------| -| `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | -| `HeaderFilterRegex` | `.*` | Checks apply to all headers, not just implementation files | -| `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | -| `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | -| `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | -| `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | -| `readability-braces-around-statements.ShortStatementLines` | `2` | Single-line bodies up to 2 lines may omit braces | +| Option | Value | Effect | +| ---------------------------------------------------------- | ---------------- | -------------------------------------------------------------- | +| `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | +| `HeaderFilterRegex` | `.*` | Checks apply to all headers, not just implementation files | +| `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | +| `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | +| `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | +| `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | +| `readability-braces-around-statements.ShortStatementLines` | `2` | Single-line bodies up to 2 lines may omit braces | From 4a3beac2b24b062842eb520900c8592605a5402b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 21:01:20 +0000 Subject: [PATCH 030/148] Update guidance --- .clang-tidy | 8 +++++++- docs/cpp_style_guide.md | 17 +++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 279b7f030..3198f4627 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -40,6 +40,12 @@ WarningsAsErrors: '*' HeaderFilterRegex: '.*' FormatStyle: none User: jenkins +# CheckOptions: per-check tuning parameters. Each entry configures a specific +# option for an individual check, using the form: +# key: . +# value: +# These let you adjust thresholds, naming patterns, and behavior without +# enabling or disabling the check entirely. CheckOptions: - key: bugprone-argument-comment.StrictMode value: '0' @@ -142,7 +148,7 @@ CheckOptions: - key: performance-type-promotion-in-math-fn.IncludeStyle value: llvm - key: readability-braces-around-statements.ShortStatementLines - value: '2' + value: '0' - key: readability-function-size.BranchThreshold value: '4294967295' - key: readability-function-size.LineThreshold diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 4aa0c30c1..8fc84296e 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -5,16 +5,13 @@ GiGL enforces C++ style automatically via two tools: - **clang-format** (`.clang-format`) — code formatting - **clang-tidy** (`.clang-tidy`) — static analysis and lint -Both run as part of CI. All clang-tidy warnings are treated as errors. +All clang-tidy warnings are treated as errors. ## Running the Tools ```bash -# Format all C++ files in-place -clang-format -i $(find gigl/csrc -name '*.cpp' -o -name '*.h') - -# Run static analysis -clang-tidy gigl/csrc/**/*.cpp +make format_cpp # Format all C++ files in-place +make lint_cpp # Run clang-tidy static analysis ``` ______________________________________________________________________ @@ -99,11 +96,11 @@ Enabled families: | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | | `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | -| `cert-*` (selected) | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | +| `cert-*` | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | | `clang-analyzer-*` | Clang static analyzer: memory safety, null dereferences, use-after-free, etc. | | `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks | -| `cppcoreguidelines-*` (selected) | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | -| `google-*` (selected) | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | +| `cppcoreguidelines-*` | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | +| `google-*` | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | | `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | | `misc-*` | Miscellaneous: header-only definitions, suspicious enum usage, throw-by-value/catch-by-reference, etc. | | `modernize-*` | Modernize to C++11/14/17: `nullptr`, range-based for, `make_unique`, `using` aliases, etc. | @@ -150,4 +147,4 @@ Enforced via `readability-identifier-naming`: | `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | | `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | | `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | -| `readability-braces-around-statements.ShortStatementLines` | `2` | Single-line bodies up to 2 lines may omit braces | +| `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | From cffa7ba35bcc996e0ac815656fb2ca4924d126d9 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 21:01:20 +0000 Subject: [PATCH 031/148] Update guidance --- .clang-tidy | 8 +++++++- docs/cpp_style_guide.md | 17 +++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 279b7f030..3198f4627 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -40,6 +40,12 @@ WarningsAsErrors: '*' HeaderFilterRegex: '.*' FormatStyle: none User: jenkins +# CheckOptions: per-check tuning parameters. Each entry configures a specific +# option for an individual check, using the form: +# key: . +# value: +# These let you adjust thresholds, naming patterns, and behavior without +# enabling or disabling the check entirely. CheckOptions: - key: bugprone-argument-comment.StrictMode value: '0' @@ -142,7 +148,7 @@ CheckOptions: - key: performance-type-promotion-in-math-fn.IncludeStyle value: llvm - key: readability-braces-around-statements.ShortStatementLines - value: '2' + value: '0' - key: readability-function-size.BranchThreshold value: '4294967295' - key: readability-function-size.LineThreshold diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 4aa0c30c1..8fc84296e 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -5,16 +5,13 @@ GiGL enforces C++ style automatically via two tools: - **clang-format** (`.clang-format`) — code formatting - **clang-tidy** (`.clang-tidy`) — static analysis and lint -Both run as part of CI. All clang-tidy warnings are treated as errors. +All clang-tidy warnings are treated as errors. ## Running the Tools ```bash -# Format all C++ files in-place -clang-format -i $(find gigl/csrc -name '*.cpp' -o -name '*.h') - -# Run static analysis -clang-tidy gigl/csrc/**/*.cpp +make format_cpp # Format all C++ files in-place +make lint_cpp # Run clang-tidy static analysis ``` ______________________________________________________________________ @@ -99,11 +96,11 @@ Enabled families: | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | | `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | -| `cert-*` (selected) | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | +| `cert-*` | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | | `clang-analyzer-*` | Clang static analyzer: memory safety, null dereferences, use-after-free, etc. | | `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks | -| `cppcoreguidelines-*` (selected) | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | -| `google-*` (selected) | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | +| `cppcoreguidelines-*` | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | +| `google-*` | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | | `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | | `misc-*` | Miscellaneous: header-only definitions, suspicious enum usage, throw-by-value/catch-by-reference, etc. | | `modernize-*` | Modernize to C++11/14/17: `nullptr`, range-based for, `make_unique`, `using` aliases, etc. | @@ -150,4 +147,4 @@ Enforced via `readability-identifier-naming`: | `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | | `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | | `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | -| `readability-braces-around-statements.ShortStatementLines` | `2` | Single-line bodies up to 2 lines may omit braces | +| `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | From 1d1dbfd290c2106044aa2035c9dceb744f586ba9 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 21:38:11 +0000 Subject: [PATCH 032/148] Update --- Makefile | 4 +-- gigl/scripts/post_install.py | 47 +++++++--------------------- requirements/install_cpp_deps.sh | 12 ++++--- scripts/build_cpp_extensions.py | 10 +++--- scripts/cpp_build_constants.py | 17 ++++++++++ scripts/generate_compile_commands.py | 38 ++++++++-------------- 6 files changed, 55 insertions(+), 73 deletions(-) create mode 100644 scripts/cpp_build_constants.py diff --git a/Makefile b/Makefile index 28bbd3d18..79e2a02ba 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ assert_yaml_configs_parse: # Ex. `make unit_test_py PY_TEST_FILES="eval_metrics_test.py"` # By default, runs all tests under tests/unit. # See the help text for "--test_file_pattern" in tests/test_args.py for more details. -unit_test_py: clean_build_files_py type_check build_cpp_extensions +unit_test_py: clean_build_files_py build_cpp_extensions type_check uv run python -m tests.unit.main \ --env=test \ --resource_config_uri=${GIGL_TEST_DEFAULT_RESOURCE_CONFIG} \ @@ -119,7 +119,7 @@ check_format_md: check_format_cpp: $(if $(CPP_SOURCES), clang-format --dry-run --Werror --style=file $(CPP_SOURCES)) -check_format: check_format_py check_format_scala check_format_md check_format_cpp +check_format: check_format_py check_format_cpp check_format_scala check_format_md # Set PY_TEST_FILES= to test a specifc file. # Ex. `make integration_test PY_TEST_FILES="dataflow_test.py"` diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index d31b4244a..bafc4ae21 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -11,28 +11,6 @@ import subprocess import sys from pathlib import Path -from typing import Optional - - -def run_command_and_stream_stdout(cmd: str) -> Optional[int]: - """ - Executes a command and streams the stdout output. - - Args: - cmd (str): The command to be executed. - - Returns: - Optional[int]: The return code of the command, or None if the command failed to execute. - """ - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) - while True: - output = process.stdout.readline() # type: ignore - if output == b"" and process.poll() is not None: - break - if output: - print(output.strip()) - return_code: Optional[int] = process.poll() - return return_code def main(): @@ -49,26 +27,26 @@ def main(): sys.exit(1) try: - print(f"Executing bash {install_glt_script}...") - result = run_command_and_stream_stdout(f"bash {install_glt_script}") - print("GLT install finished with return code:", result) - except Exception as e: - print(f"Unexpected error: {e}") + print(f"Installing GLT via {install_glt_script}...") + subprocess.run(["bash", str(install_glt_script)], check=True) + print("GLT install finished.") + except subprocess.CalledProcessError as e: + print(f"Error installing GLT: {e}") sys.exit(1) # Step 2: Build pybind11 C++ extensions in-place so they are importable # without requiring a separate `make build_cpp_extensions` call. # subprocess.run streams stdout/stderr to the terminal and raises # CalledProcessError on a non-zero exit code. + build_cpp_script = repo_root / "scripts" / "build_cpp_extensions.py" + if not build_cpp_script.exists(): + print(f"Error: build_cpp_extensions.py not found at {build_cpp_script}") + sys.exit(1) + try: print("Building C++ extensions...") subprocess.run( - [ - sys.executable, - "scripts/build_cpp_extensions.py", - "build_ext", - "--inplace", - ], + [sys.executable, str(build_cpp_script), "build_ext", "--inplace"], cwd=repo_root, check=True, ) @@ -76,9 +54,6 @@ def main(): except subprocess.CalledProcessError as e: print(f"Error building C++ extensions: {e}") sys.exit(1) - except Exception as e: - print(f"Unexpected error building C++ extensions: {e}") - sys.exit(1) if __name__ == "__main__": diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 6b9f19113..1e1a6cf16 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -6,10 +6,15 @@ # # Called by `make install_dev_deps` alongside install_py_deps.sh and # install_scala_deps.sh. +# +# NOTE: On Linux, this script calls apt-get and update-alternatives, which +# require root privileges. Run as root or prefix with sudo. set -e set -x +CLANG_VERSION=15 + is_running_on_mac() { [ "$(uname)" == "Darwin" ] return $? @@ -35,12 +40,11 @@ if is_running_on_mac; then # install_dev_deps to pick up the PATH change. export PATH="$LLVM_BIN:$PATH" else - # Ubuntu / Debian — clang 15 is the highest version available on Ubuntu 22.04. - apt-get install -y clang-format-15 clang-tidy-15 cmake + apt-get install -y "clang-format-${CLANG_VERSION}" "clang-tidy-${CLANG_VERSION}" cmake # Register versioned binaries as the default so bare `clang-format` and # `clang-tidy` resolve to them without callers specifying the version suffix. - update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100 - update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 100 + update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-${CLANG_VERSION}" 100 + update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-${CLANG_VERSION}" 100 fi echo "Finished installing C++ tooling" diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index 5bc3dd8bf..14a6d3911 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -8,13 +8,11 @@ python build_cpp_extensions.py build_ext --inplace """ -from pathlib import Path - from setuptools import setup from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension -_CSRC_DIR = Path("gigl/csrc") +from cpp_build_constants import COMPILE_ARGS, CSRC_DIR def find_cpp_extensions() -> list[Extension]: @@ -25,10 +23,10 @@ def find_cpp_extensions() -> list[Extension]: Returns an empty list if ``gigl/csrc/`` does not yet exist. """ - if not _CSRC_DIR.exists(): + if not CSRC_DIR.exists(): return [] extensions = [] - for cpp_file in sorted(_CSRC_DIR.rglob("python_*.cpp")): + for cpp_file in sorted(CSRC_DIR.rglob("python_*.cpp")): parts = list(cpp_file.with_suffix("").parts) parts[-1] = parts[-1].removeprefix("python_") module_name = ".".join(parts) @@ -40,7 +38,7 @@ def find_cpp_extensions() -> list[Extension]: CppExtension( name=module_name, sources=sources, - extra_compile_args=["-O3", "-std=c++17", "-Wall", "-Wextra"], + extra_compile_args=COMPILE_ARGS, ) ) return extensions diff --git a/scripts/cpp_build_constants.py b/scripts/cpp_build_constants.py new file mode 100644 index 000000000..ab1c7cc36 --- /dev/null +++ b/scripts/cpp_build_constants.py @@ -0,0 +1,17 @@ +"""Shared C++ build constants for build_cpp_extensions.py and generate_compile_commands.py. + +This is the single source of truth for C++ compiler flags and source paths. +Both scripts import from here so clang-tidy always analyzes with the same flags +used during the actual build. +""" + +from pathlib import Path + +# REPO_ROOT is derived from this file's location — this file must live in scripts/. +REPO_ROOT: Path = Path(__file__).resolve().parent.parent +CSRC_DIR: Path = REPO_ROOT / "gigl" / "csrc" + +# Flags passed to every C++ compilation unit. Applies to both the extension +# build (build_cpp_extensions.py) and the compile_commands.json used by +# clang-tidy (generate_compile_commands.py). +COMPILE_ARGS: list[str] = ["-O3", "-std=c++17", "-Wall", "-Wextra"] diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index eec176848..d42d52682 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -9,58 +9,46 @@ uv run python scripts/generate_compile_commands.py Output: ``build/compile_commands.json`` (created or overwritten). + +Note: run ``make build_cpp_extensions`` before this script (or use ``make lint_cpp``, +which does both in the correct order) so the database reflects the current build state. """ import json -import subprocess import sys import sysconfig -from pathlib import Path from torch.utils.cpp_extension import include_paths as torch_include_paths +from cpp_build_constants import COMPILE_ARGS, CSRC_DIR, REPO_ROOT -def main() -> None: - repo_root = Path(__file__).parent.parent.resolve() - - # Always rebuild C++ extensions before generating compile_commands.json so - # the database reflects the current state of the code. - subprocess.run( - [sys.executable, "scripts/build_cpp_extensions.py", "build_ext", "--inplace"], - cwd=repo_root, - check=True, - ) +def main() -> None: # Collect all include directories needed to compile the extension. # torch_include_paths() returns the torch headers, which already bundle # pybind11 under torch/include/pybind11/ — no separate pybind11 import needed. - include_flags: list[str] = [] - for path in torch_include_paths(): - include_flags.append(f"-I{path}") + include_flags: list[str] = [f"-I{path}" for path in torch_include_paths()] # Python C API headers (e.g. Python.h) required by pybind11. include_flags.append(f"-I{sysconfig.get_path('include')}") - cpp_dir = repo_root / "gigl" / "csrc" - cpp_sources = sorted(cpp_dir.rglob("*.cpp")) if cpp_dir.exists() else [] + cpp_sources = sorted(CSRC_DIR.rglob("*.cpp")) if CSRC_DIR.exists() else [] if not cpp_sources: - print("Warning: no .cpp files found under gigl/csrc/", file=sys.stderr) + print(f"Warning: no .cpp files found under {CSRC_DIR}", file=sys.stderr) + + cxx_flags = " ".join(COMPILE_ARGS) # Each entry in compile_commands.json describes how one source file is compiled. # clang-tidy reads this to reproduce the exact compilation environment. commands: list[dict[str, str]] = [ { - "directory": str(repo_root), + "directory": str(REPO_ROOT), "file": str(source), - "command": ( - f"c++ -std=c++17 -Wall -Wextra " - f"{' '.join(include_flags)} " - f"-c {source}" - ), + "command": f"c++ {cxx_flags} {' '.join(include_flags)} -c {source}", } for source in cpp_sources ] - output = repo_root / "build" / "compile_commands.json" + output = REPO_ROOT / "build" / "compile_commands.json" output.parent.mkdir(exist_ok=True) output.write_text(json.dumps(commands, indent=2)) print( From 49e949719d1f6c3c8dc9f462823598ed011d1282 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 21:38:11 +0000 Subject: [PATCH 033/148] Update --- Makefile | 4 +-- gigl/scripts/post_install.py | 47 +++++++--------------------- requirements/install_cpp_deps.sh | 12 ++++--- scripts/build_cpp_extensions.py | 10 +++--- scripts/cpp_build_constants.py | 17 ++++++++++ scripts/generate_compile_commands.py | 38 ++++++++-------------- 6 files changed, 55 insertions(+), 73 deletions(-) create mode 100644 scripts/cpp_build_constants.py diff --git a/Makefile b/Makefile index 28bbd3d18..79e2a02ba 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ assert_yaml_configs_parse: # Ex. `make unit_test_py PY_TEST_FILES="eval_metrics_test.py"` # By default, runs all tests under tests/unit. # See the help text for "--test_file_pattern" in tests/test_args.py for more details. -unit_test_py: clean_build_files_py type_check build_cpp_extensions +unit_test_py: clean_build_files_py build_cpp_extensions type_check uv run python -m tests.unit.main \ --env=test \ --resource_config_uri=${GIGL_TEST_DEFAULT_RESOURCE_CONFIG} \ @@ -119,7 +119,7 @@ check_format_md: check_format_cpp: $(if $(CPP_SOURCES), clang-format --dry-run --Werror --style=file $(CPP_SOURCES)) -check_format: check_format_py check_format_scala check_format_md check_format_cpp +check_format: check_format_py check_format_cpp check_format_scala check_format_md # Set PY_TEST_FILES= to test a specifc file. # Ex. `make integration_test PY_TEST_FILES="dataflow_test.py"` diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index d31b4244a..bafc4ae21 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -11,28 +11,6 @@ import subprocess import sys from pathlib import Path -from typing import Optional - - -def run_command_and_stream_stdout(cmd: str) -> Optional[int]: - """ - Executes a command and streams the stdout output. - - Args: - cmd (str): The command to be executed. - - Returns: - Optional[int]: The return code of the command, or None if the command failed to execute. - """ - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) - while True: - output = process.stdout.readline() # type: ignore - if output == b"" and process.poll() is not None: - break - if output: - print(output.strip()) - return_code: Optional[int] = process.poll() - return return_code def main(): @@ -49,26 +27,26 @@ def main(): sys.exit(1) try: - print(f"Executing bash {install_glt_script}...") - result = run_command_and_stream_stdout(f"bash {install_glt_script}") - print("GLT install finished with return code:", result) - except Exception as e: - print(f"Unexpected error: {e}") + print(f"Installing GLT via {install_glt_script}...") + subprocess.run(["bash", str(install_glt_script)], check=True) + print("GLT install finished.") + except subprocess.CalledProcessError as e: + print(f"Error installing GLT: {e}") sys.exit(1) # Step 2: Build pybind11 C++ extensions in-place so they are importable # without requiring a separate `make build_cpp_extensions` call. # subprocess.run streams stdout/stderr to the terminal and raises # CalledProcessError on a non-zero exit code. + build_cpp_script = repo_root / "scripts" / "build_cpp_extensions.py" + if not build_cpp_script.exists(): + print(f"Error: build_cpp_extensions.py not found at {build_cpp_script}") + sys.exit(1) + try: print("Building C++ extensions...") subprocess.run( - [ - sys.executable, - "scripts/build_cpp_extensions.py", - "build_ext", - "--inplace", - ], + [sys.executable, str(build_cpp_script), "build_ext", "--inplace"], cwd=repo_root, check=True, ) @@ -76,9 +54,6 @@ def main(): except subprocess.CalledProcessError as e: print(f"Error building C++ extensions: {e}") sys.exit(1) - except Exception as e: - print(f"Unexpected error building C++ extensions: {e}") - sys.exit(1) if __name__ == "__main__": diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 6b9f19113..1e1a6cf16 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -6,10 +6,15 @@ # # Called by `make install_dev_deps` alongside install_py_deps.sh and # install_scala_deps.sh. +# +# NOTE: On Linux, this script calls apt-get and update-alternatives, which +# require root privileges. Run as root or prefix with sudo. set -e set -x +CLANG_VERSION=15 + is_running_on_mac() { [ "$(uname)" == "Darwin" ] return $? @@ -35,12 +40,11 @@ if is_running_on_mac; then # install_dev_deps to pick up the PATH change. export PATH="$LLVM_BIN:$PATH" else - # Ubuntu / Debian — clang 15 is the highest version available on Ubuntu 22.04. - apt-get install -y clang-format-15 clang-tidy-15 cmake + apt-get install -y "clang-format-${CLANG_VERSION}" "clang-tidy-${CLANG_VERSION}" cmake # Register versioned binaries as the default so bare `clang-format` and # `clang-tidy` resolve to them without callers specifying the version suffix. - update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100 - update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 100 + update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-${CLANG_VERSION}" 100 + update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-${CLANG_VERSION}" 100 fi echo "Finished installing C++ tooling" diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index 5bc3dd8bf..14a6d3911 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -8,13 +8,11 @@ python build_cpp_extensions.py build_ext --inplace """ -from pathlib import Path - from setuptools import setup from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension -_CSRC_DIR = Path("gigl/csrc") +from cpp_build_constants import COMPILE_ARGS, CSRC_DIR def find_cpp_extensions() -> list[Extension]: @@ -25,10 +23,10 @@ def find_cpp_extensions() -> list[Extension]: Returns an empty list if ``gigl/csrc/`` does not yet exist. """ - if not _CSRC_DIR.exists(): + if not CSRC_DIR.exists(): return [] extensions = [] - for cpp_file in sorted(_CSRC_DIR.rglob("python_*.cpp")): + for cpp_file in sorted(CSRC_DIR.rglob("python_*.cpp")): parts = list(cpp_file.with_suffix("").parts) parts[-1] = parts[-1].removeprefix("python_") module_name = ".".join(parts) @@ -40,7 +38,7 @@ def find_cpp_extensions() -> list[Extension]: CppExtension( name=module_name, sources=sources, - extra_compile_args=["-O3", "-std=c++17", "-Wall", "-Wextra"], + extra_compile_args=COMPILE_ARGS, ) ) return extensions diff --git a/scripts/cpp_build_constants.py b/scripts/cpp_build_constants.py new file mode 100644 index 000000000..ab1c7cc36 --- /dev/null +++ b/scripts/cpp_build_constants.py @@ -0,0 +1,17 @@ +"""Shared C++ build constants for build_cpp_extensions.py and generate_compile_commands.py. + +This is the single source of truth for C++ compiler flags and source paths. +Both scripts import from here so clang-tidy always analyzes with the same flags +used during the actual build. +""" + +from pathlib import Path + +# REPO_ROOT is derived from this file's location — this file must live in scripts/. +REPO_ROOT: Path = Path(__file__).resolve().parent.parent +CSRC_DIR: Path = REPO_ROOT / "gigl" / "csrc" + +# Flags passed to every C++ compilation unit. Applies to both the extension +# build (build_cpp_extensions.py) and the compile_commands.json used by +# clang-tidy (generate_compile_commands.py). +COMPILE_ARGS: list[str] = ["-O3", "-std=c++17", "-Wall", "-Wextra"] diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index eec176848..d42d52682 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -9,58 +9,46 @@ uv run python scripts/generate_compile_commands.py Output: ``build/compile_commands.json`` (created or overwritten). + +Note: run ``make build_cpp_extensions`` before this script (or use ``make lint_cpp``, +which does both in the correct order) so the database reflects the current build state. """ import json -import subprocess import sys import sysconfig -from pathlib import Path from torch.utils.cpp_extension import include_paths as torch_include_paths +from cpp_build_constants import COMPILE_ARGS, CSRC_DIR, REPO_ROOT -def main() -> None: - repo_root = Path(__file__).parent.parent.resolve() - - # Always rebuild C++ extensions before generating compile_commands.json so - # the database reflects the current state of the code. - subprocess.run( - [sys.executable, "scripts/build_cpp_extensions.py", "build_ext", "--inplace"], - cwd=repo_root, - check=True, - ) +def main() -> None: # Collect all include directories needed to compile the extension. # torch_include_paths() returns the torch headers, which already bundle # pybind11 under torch/include/pybind11/ — no separate pybind11 import needed. - include_flags: list[str] = [] - for path in torch_include_paths(): - include_flags.append(f"-I{path}") + include_flags: list[str] = [f"-I{path}" for path in torch_include_paths()] # Python C API headers (e.g. Python.h) required by pybind11. include_flags.append(f"-I{sysconfig.get_path('include')}") - cpp_dir = repo_root / "gigl" / "csrc" - cpp_sources = sorted(cpp_dir.rglob("*.cpp")) if cpp_dir.exists() else [] + cpp_sources = sorted(CSRC_DIR.rglob("*.cpp")) if CSRC_DIR.exists() else [] if not cpp_sources: - print("Warning: no .cpp files found under gigl/csrc/", file=sys.stderr) + print(f"Warning: no .cpp files found under {CSRC_DIR}", file=sys.stderr) + + cxx_flags = " ".join(COMPILE_ARGS) # Each entry in compile_commands.json describes how one source file is compiled. # clang-tidy reads this to reproduce the exact compilation environment. commands: list[dict[str, str]] = [ { - "directory": str(repo_root), + "directory": str(REPO_ROOT), "file": str(source), - "command": ( - f"c++ -std=c++17 -Wall -Wextra " - f"{' '.join(include_flags)} " - f"-c {source}" - ), + "command": f"c++ {cxx_flags} {' '.join(include_flags)} -c {source}", } for source in cpp_sources ] - output = repo_root / "build" / "compile_commands.json" + output = REPO_ROOT / "build" / "compile_commands.json" output.parent.mkdir(exist_ok=True) output.write_text(json.dumps(commands, indent=2)) print( From 3e1bf6b294e39143126fa05fd906c5d154cc426b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 21:52:42 +0000 Subject: [PATCH 034/148] Fix --- scripts/build_cpp_extensions.py | 2 +- scripts/generate_compile_commands.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index 14a6d3911..264fb7fb7 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -12,7 +12,7 @@ from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension -from cpp_build_constants import COMPILE_ARGS, CSRC_DIR +from scripts.cpp_build_constants import COMPILE_ARGS, CSRC_DIR def find_cpp_extensions() -> list[Extension]: diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index d42d52682..17c00b93a 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -20,7 +20,7 @@ from torch.utils.cpp_extension import include_paths as torch_include_paths -from cpp_build_constants import COMPILE_ARGS, CSRC_DIR, REPO_ROOT +from scripts.cpp_build_constants import COMPILE_ARGS, CSRC_DIR, REPO_ROOT def main() -> None: From 7fd3ed9f93e428155ffed831d9d7500a19d9c542 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 22:09:18 +0000 Subject: [PATCH 035/148] Fix --- {scripts => gigl}/cpp_build_constants.py | 7 +++++-- scripts/build_cpp_extensions.py | 2 +- scripts/generate_compile_commands.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) rename {scripts => gigl}/cpp_build_constants.py (73%) diff --git a/scripts/cpp_build_constants.py b/gigl/cpp_build_constants.py similarity index 73% rename from scripts/cpp_build_constants.py rename to gigl/cpp_build_constants.py index ab1c7cc36..6cc8245db 100644 --- a/scripts/cpp_build_constants.py +++ b/gigl/cpp_build_constants.py @@ -7,11 +7,14 @@ from pathlib import Path -# REPO_ROOT is derived from this file's location — this file must live in scripts/. +# REPO_ROOT is derived from this file's location — this file must live in gigl/. REPO_ROOT: Path = Path(__file__).resolve().parent.parent CSRC_DIR: Path = REPO_ROOT / "gigl" / "csrc" # Flags passed to every C++ compilation unit. Applies to both the extension # build (build_cpp_extensions.py) and the compile_commands.json used by # clang-tidy (generate_compile_commands.py). -COMPILE_ARGS: list[str] = ["-O3", "-std=c++17", "-Wall", "-Wextra"] +# -Wno-unused-parameter suppresses noise from third-party headers (e.g. PyTorch) +# that don't compile cleanly under -Wextra. Unused parameters in our own code +# are still caught by clang-tidy's bugprone-* checks. +COMPILE_ARGS: list[str] = ["-O3", "-std=c++17", "-Wall", "-Wextra", "-Wno-unused-parameter"] diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index 264fb7fb7..b63a20634 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -12,7 +12,7 @@ from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension -from scripts.cpp_build_constants import COMPILE_ARGS, CSRC_DIR +from gigl.cpp_build_constants import COMPILE_ARGS, CSRC_DIR def find_cpp_extensions() -> list[Extension]: diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 17c00b93a..f6bdad0bb 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -20,7 +20,7 @@ from torch.utils.cpp_extension import include_paths as torch_include_paths -from scripts.cpp_build_constants import COMPILE_ARGS, CSRC_DIR, REPO_ROOT +from gigl.cpp_build_constants import COMPILE_ARGS, CSRC_DIR, REPO_ROOT def main() -> None: From a682ded4a5d834f1628f99e4d03b6c52dbb4f97c Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 10 Apr 2026 22:15:36 +0000 Subject: [PATCH 036/148] Update --- gigl/cpp_build_constants.py | 8 +++++++- requirements/install_cpp_deps.sh | 14 +++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/gigl/cpp_build_constants.py b/gigl/cpp_build_constants.py index 6cc8245db..b638eb8f6 100644 --- a/gigl/cpp_build_constants.py +++ b/gigl/cpp_build_constants.py @@ -17,4 +17,10 @@ # -Wno-unused-parameter suppresses noise from third-party headers (e.g. PyTorch) # that don't compile cleanly under -Wextra. Unused parameters in our own code # are still caught by clang-tidy's bugprone-* checks. -COMPILE_ARGS: list[str] = ["-O3", "-std=c++17", "-Wall", "-Wextra", "-Wno-unused-parameter"] +COMPILE_ARGS: list[str] = [ + "-O3", + "-std=c++17", + "-Wall", + "-Wextra", + "-Wno-unused-parameter", +] diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 1e1a6cf16..796f34aef 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -21,9 +21,11 @@ is_running_on_mac() { } if is_running_on_mac; then - # `brew install llvm` provides clang-format and clang-tidy. - # Homebrew does not add llvm to PATH by default to avoid shadowing Apple's - # clang, so we add it ourselves. + # macOS ships its own Apple Clang via Xcode Command Line Tools. Homebrew + # intentionally does not put its llvm binaries on PATH to avoid shadowing + # Apple's clang. We therefore have to add the Homebrew llvm bin directory + # to PATH ourselves so that `clang-format` and `clang-tidy` resolve to the + # Homebrew versions rather than being missing entirely. brew install llvm cmake LLVM_BIN="$(brew --prefix llvm)/bin" @@ -40,9 +42,11 @@ if is_running_on_mac; then # install_dev_deps to pick up the PATH change. export PATH="$LLVM_BIN:$PATH" else + # On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly + # into /usr/bin. update-alternatives wires up the bare names (clang-format, + # clang-tidy) so callers don't need to specify the version suffix. No PATH + # changes are needed since /usr/bin is already on PATH. apt-get install -y "clang-format-${CLANG_VERSION}" "clang-tidy-${CLANG_VERSION}" cmake - # Register versioned binaries as the default so bare `clang-format` and - # `clang-tidy` resolve to them without callers specifying the version suffix. update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-${CLANG_VERSION}" 100 update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-${CLANG_VERSION}" 100 fi From fe2cc0b672df8a25e531a90f2c95e023df5485d0 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 14 Apr 2026 00:05:43 +0000 Subject: [PATCH 037/148] Update type check --- gigl/csrc/sampling/ppr_forward_push.cpp | 284 +++++++++--------- gigl/csrc/sampling/ppr_forward_push.h | 87 +++--- .../csrc/sampling/python_ppr_forward_push.cpp | 34 +-- 3 files changed, 210 insertions(+), 195 deletions(-) diff --git a/gigl/csrc/sampling/ppr_forward_push.cpp b/gigl/csrc/sampling/ppr_forward_push.cpp index 436967cd7..f97b2f40c 100644 --- a/gigl/csrc/sampling/ppr_forward_push.cpp +++ b/gigl/csrc/sampling/ppr_forward_push.cpp @@ -1,209 +1,218 @@ #include "ppr_forward_push.h" -PPRForwardPushState::PPRForwardPushState(torch::Tensor seed_nodes, - int32_t seed_node_type_id, +PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, + int32_t seedNodeTypeId, double alpha, - double requeue_threshold_factor, - std::vector> node_type_to_edge_type_ids, - std::vector edge_type_to_dst_ntype_id, - std::vector degree_tensors) - : alpha_(alpha), - one_minus_alpha_(1.0 - alpha), - requeue_threshold_factor_(requeue_threshold_factor), + double requeueThresholdFactor, + std::vector> nodeTypeToEdgeTypeIds, + std::vector edgeTypeToDstNtypeId, + std::vector degreeTensors) + : _alpha(alpha), + _oneMinusAlpha(1.0 - alpha), + _requeueThresholdFactor(requeueThresholdFactor), // std::move transfers ownership of each vector into the member variable // without copying its contents — equivalent to Python's list hand-off // when you no longer need the original. - node_type_to_edge_type_ids_(std::move(node_type_to_edge_type_ids)), - edge_type_to_dst_ntype_id_(std::move(edge_type_to_dst_ntype_id)), - degree_tensors_(std::move(degree_tensors)) { - TORCH_CHECK(seed_nodes.dim() == 1, "seed_nodes must be 1D"); - batch_size_ = static_cast(seed_nodes.size(0)); - num_node_types_ = static_cast(node_type_to_edge_type_ids_.size()); + _nodeTypeToEdgeTypeIds(std::move(nodeTypeToEdgeTypeIds)), + _edgeTypeToDstNtypeId(std::move(edgeTypeToDstNtypeId)), + _degreeTensors(std::move(degreeTensors)) { + TORCH_CHECK(seedNodes.dim() == 1, "seedNodes must be 1D"); + _batchSize = static_cast(seedNodes.size(0)); + _numNodeTypes = static_cast(_nodeTypeToEdgeTypeIds.size()); // Allocate per-seed, per-node-type tables. // .assign(n, val) fills a vector with n copies of val — like [val] * n in Python. - ppr_scores_.assign(batch_size_, std::vector>(num_node_types_)); - residuals_.assign(batch_size_, std::vector>(num_node_types_)); - queue_.assign(batch_size_, std::vector>(num_node_types_)); - queued_nodes_.assign(batch_size_, std::vector>(num_node_types_)); + _pprScores.assign(_batchSize, std::vector>(_numNodeTypes)); + _residuals.assign(_batchSize, std::vector>(_numNodeTypes)); + _queue.assign(_batchSize, std::vector>(_numNodeTypes)); + _queuedNodes.assign(_batchSize, std::vector>(_numNodeTypes)); // accessor() returns a typed view into the tensor's data that // supports [i] indexing with bounds checking in debug builds. - auto acc = seed_nodes.accessor(); - num_nodes_in_queue_ = batch_size_; - for (int32_t i = 0; i < batch_size_; ++i) { - int32_t seed = static_cast(acc[i]); + auto acc = seedNodes.accessor(); + _numNodesInQueue = _batchSize; + for (int32_t i = 0; i < _batchSize; ++i) { + auto seed = static_cast(acc[i]); // PPR initialisation: each seed starts with residual = alpha (the // restart probability). The first push will move alpha into ppr_score // and distribute (1-alpha)*alpha to the seed's neighbors. - residuals_[i][seed_node_type_id][seed] = alpha_; - queue_[i][seed_node_type_id].insert(seed); + _residuals[i][seedNodeTypeId][seed] = _alpha; + _queue[i][seedNodeTypeId].insert(seed); } } -std::optional> PPRForwardPushState::drain_queue() { - if (num_nodes_in_queue_ == 0) { +std::optional> PPRForwardPushState::drainQueue() { + if (_numNodesInQueue == 0) { return std::nullopt; } // Reset the snapshot from the previous iteration. - for (int32_t s = 0; s < batch_size_; ++s) - for (auto& qs : queued_nodes_[s]) + for (int32_t s = 0; s < _batchSize; ++s) { + for (auto& qs : _queuedNodes[s]) { qs.clear(); + } + } - // nodes_to_lookup[eid] = set of node IDs that need a neighbor fetch for + // nodesToLookup[eid] = set of node IDs that need a neighbor fetch for // edge type eid this round. Using a set deduplicates nodes that appear // in multiple seeds' queues: we only fetch each (node, etype) pair once. - std::unordered_map> nodes_to_lookup; + std::unordered_map> nodesToLookup; - int32_t total_drained_this_round = 0; - for (int32_t s = 0; s < batch_size_; ++s) { - for (int32_t nt = 0; nt < num_node_types_; ++nt) { - if (queue_[s][nt].empty()) + int32_t totalDrainedThisRound = 0; + for (int32_t s = 0; s < _batchSize; ++s) { + for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { + if (_queue[s][nt].empty()) { continue; + } // Move the live queue into the snapshot (no data copy — O(1)). - queued_nodes_[s][nt] = std::move(queue_[s][nt]); - queue_[s][nt].clear(); - total_drained_this_round += static_cast(queued_nodes_[s][nt].size()); - num_nodes_in_queue_ -= static_cast(queued_nodes_[s][nt].size()); - - for (int32_t node_id : queued_nodes_[s][nt]) { - for (int32_t eid : node_type_to_edge_type_ids_[nt]) { - if (neighbor_cache_.find(pack_key(node_id, eid)) == neighbor_cache_.end()) { - nodes_to_lookup[eid].insert(node_id); + _queuedNodes[s][nt] = std::move(_queue[s][nt]); + _queue[s][nt].clear(); + totalDrainedThisRound += static_cast(_queuedNodes[s][nt].size()); + _numNodesInQueue -= static_cast(_queuedNodes[s][nt].size()); + + for (int32_t nodeId : _queuedNodes[s][nt]) { + for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { + if (_neighborCache.find(packKey(nodeId, eid)) == _neighborCache.end()) { + nodesToLookup[eid].insert(nodeId); } } } } } - nodes_drained_per_iteration_.push_back(total_drained_this_round); + _nodesDrainedPerIteration.push_back(totalDrainedThisRound); std::unordered_map result; - for (auto& [eid, node_set] : nodes_to_lookup) { - std::vector ids(node_set.begin(), node_set.end()); + for (auto& [eid, nodeSet] : nodesToLookup) { + std::vector ids(nodeSet.begin(), nodeSet.end()); result[eid] = torch::tensor(ids, torch::kLong); } return result; } -const std::vector& PPRForwardPushState::get_nodes_drained_per_iteration() const { - return nodes_drained_per_iteration_; +const std::vector& PPRForwardPushState::getNodesDrainedPerIteration() const { + return _nodesDrainedPerIteration; } -void PPRForwardPushState::push_residuals( - const std::unordered_map>& fetched_by_etype_id) { - // Step 1: Unpack the input map into a C++ map keyed by pack_key(node_id, etype_id) +void PPRForwardPushState::pushResiduals( + const std::unordered_map>& fetchedByEtypeId) { + // Step 1: Unpack the input map into a C++ map keyed by packKey(nodeId, etypeId) // for fast lookup during the residual-push loop below. std::unordered_map> fetched; - for (const auto& [eid, tup] : fetched_by_etype_id) { - const auto& node_ids_t = std::get<0>(tup); - const auto& flat_nbrs_t = std::get<1>(tup); - const auto& counts_t = std::get<2>(tup); + for (const auto& [eid, tup] : fetchedByEtypeId) { + const auto& nodeIdsT = std::get<0>(tup); + const auto& flatNbrsT = std::get<1>(tup); + const auto& countsT = std::get<2>(tup); // accessor() gives a bounds-checked, typed 1-D view into // each tensor's data — equivalent to iterating over a NumPy array. - auto node_acc = node_ids_t.accessor(); - auto nbr_acc = flat_nbrs_t.accessor(); - auto cnt_acc = counts_t.accessor(); + auto nodeAcc = nodeIdsT.accessor(); + auto nbrAcc = flatNbrsT.accessor(); + auto cntAcc = countsT.accessor(); // Walk the flat neighbor list, slicing out each node's neighbors using // the running offset into the concatenated flat buffer. int64_t offset = 0; - for (int64_t i = 0; i < node_ids_t.size(0); ++i) { - int32_t nid = static_cast(node_acc[i]); - int64_t count = cnt_acc[i]; + for (int64_t i = 0; i < nodeIdsT.size(0); ++i) { + auto nid = static_cast(nodeAcc[i]); + int64_t count = cntAcc[i]; std::vector nbrs(count); - for (int64_t j = 0; j < count; ++j) - nbrs[j] = static_cast(nbr_acc[offset + j]); - fetched[pack_key(nid, eid)] = std::move(nbrs); + for (int64_t j = 0; j < count; ++j) { + nbrs[j] = static_cast(nbrAcc[offset + j]); + } + fetched[packKey(nid, eid)] = std::move(nbrs); offset += count; } } - // Step 2: For every node that was in the queue (captured in queued_nodes_ - // by drain_queue()), apply one PPR push step: + // Step 2: For every node that was in the queue (captured in _queuedNodes + // by drainQueue()), apply one PPR push step: // a. Absorb residual into the PPR score. // b. Distribute (1-alpha) * residual equally to each neighbor. // c. Enqueue any neighbor whose residual now exceeds the requeue threshold. - for (int32_t s = 0; s < batch_size_; ++s) { - for (int32_t nt = 0; nt < num_node_types_; ++nt) { - if (queued_nodes_[s][nt].empty()) + for (int32_t s = 0; s < _batchSize; ++s) { + for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { + if (_queuedNodes[s][nt].empty()) { continue; + } - for (int32_t src : queued_nodes_[s][nt]) { - auto& src_res = residuals_[s][nt]; - auto it = src_res.find(src); - double res = (it != src_res.end()) ? it->second : 0.0; + for (int32_t src : _queuedNodes[s][nt]) { + auto& srcRes = _residuals[s][nt]; + auto it = srcRes.find(src); + double res = (it != srcRes.end()) ? it->second : 0.0; // a. Absorb: move residual into the PPR score. - ppr_scores_[s][nt][src] += res; - src_res[src] = 0.0; + _pprScores[s][nt][src] += res; + srcRes[src] = 0.0; // b. Count total fetched/cached neighbors across all edge types for // this source node. We normalise by the number of neighbors we // actually retrieved, not the true degree, so residual is fully // distributed among known neighbors rather than leaking to unfetched // ones (which matters when num_neighbors_per_hop < true_degree). - int32_t total_fetched = 0; - for (int32_t eid : node_type_to_edge_type_ids_[nt]) { - auto fi = fetched.find(pack_key(src, eid)); + int32_t totalFetched = 0; + for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { + auto fi = fetched.find(packKey(src, eid)); if (fi != fetched.end()) { - total_fetched += static_cast(fi->second.size()); + totalFetched += static_cast(fi->second.size()); } else { - auto ci = neighbor_cache_.find(pack_key(src, eid)); - if (ci != neighbor_cache_.end()) - total_fetched += static_cast(ci->second.size()); + auto ci = _neighborCache.find(packKey(src, eid)); + if (ci != _neighborCache.end()) { + totalFetched += static_cast(ci->second.size()); + } } } // Destination-only nodes (or nodes with no fetched neighbors) absorb // residual but do not push further. - if (total_fetched == 0) + if (totalFetched == 0) { continue; + } - double res_per_nbr = one_minus_alpha_ * res / static_cast(total_fetched); + double resPerNbr = _oneMinusAlpha * res / static_cast(totalFetched); - for (int32_t eid : node_type_to_edge_type_ids_[nt]) { - // Invariant: fetched and neighbor_cache_ are mutually exclusive for - // any given (node, etype) key within one iteration. drain_queue() - // only requests a fetch for nodes absent from neighbor_cache_, so a + for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { + // Invariant: fetched and _neighborCache are mutually exclusive for + // any given (node, etype) key within one iteration. drainQueue() + // only requests a fetch for nodes absent from _neighborCache, so a // key is in at most one of the two. - const std::vector* nbr_list = nullptr; - auto fi = fetched.find(pack_key(src, eid)); + const std::vector* nbrList = nullptr; + auto fi = fetched.find(packKey(src, eid)); if (fi != fetched.end()) { - nbr_list = &fi->second; + nbrList = &fi->second; } else { - auto ci = neighbor_cache_.find(pack_key(src, eid)); - if (ci != neighbor_cache_.end()) - nbr_list = &ci->second; + auto ci = _neighborCache.find(packKey(src, eid)); + if (ci != _neighborCache.end()) { + nbrList = &ci->second; + } } - if (!nbr_list || nbr_list->empty()) + if (!nbrList || nbrList->empty()) { continue; + } - int32_t dst_nt = edge_type_to_dst_ntype_id_[eid]; + int32_t dstNt = _edgeTypeToDstNtypeId[eid]; // c. Accumulate residual for each neighbor and re-enqueue if threshold // exceeded. - for (int32_t nbr : *nbr_list) { - residuals_[s][dst_nt][nbr] += res_per_nbr; + for (int32_t nbr : *nbrList) { + _residuals[s][dstNt][nbr] += resPerNbr; - double threshold = - requeue_threshold_factor_ * static_cast(get_total_degree(nbr, dst_nt)); + double threshold = _requeueThresholdFactor * static_cast(getTotalDegree(nbr, dstNt)); - if (queue_[s][dst_nt].find(nbr) == queue_[s][dst_nt].end() && - residuals_[s][dst_nt][nbr] >= threshold) { - queue_[s][dst_nt].insert(nbr); - ++num_nodes_in_queue_; + if (_queue[s][dstNt].find(nbr) == _queue[s][dstNt].end() && + _residuals[s][dstNt][nbr] >= threshold) { + _queue[s][dstNt].insert(nbr); + ++_numNodesInQueue; // Promote neighbor lists to the persistent cache: this node will // be processed next iteration, so caching avoids a re-fetch. - for (int32_t peid : node_type_to_edge_type_ids_[dst_nt]) { - uint64_t pk = pack_key(nbr, peid); - if (neighbor_cache_.find(pk) == neighbor_cache_.end()) { + for (int32_t peid : _nodeTypeToEdgeTypeIds[dstNt]) { + uint64_t pk = packKey(nbr, peid); + if (_neighborCache.find(pk) == _neighborCache.end()) { auto pfi = fetched.find(pk); - if (pfi != fetched.end()) - neighbor_cache_[pk] = pfi->second; + if (pfi != fetched.end()) { + _neighborCache[pk] = pfi->second; + } } } } @@ -214,23 +223,26 @@ void PPRForwardPushState::push_residuals( } } -std::unordered_map> PPRForwardPushState::extract_top_k( - int32_t max_ppr_nodes) { +std::unordered_map> PPRForwardPushState::extractTopK( + int32_t maxPprNodes) { std::unordered_set active; - for (int32_t s = 0; s < batch_size_; ++s) - for (int32_t nt = 0; nt < num_node_types_; ++nt) - if (!ppr_scores_[s][nt].empty()) + for (int32_t s = 0; s < _batchSize; ++s) { + for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { + if (!_pprScores[s][nt].empty()) { active.insert(nt); + } + } + } std::unordered_map> result; for (int32_t nt : active) { - std::vector flat_ids; - std::vector flat_weights; - std::vector valid_counts; + std::vector flatIds; + std::vector flatWeights; + std::vector validCounts; - for (int32_t s = 0; s < batch_size_; ++s) { - const auto& scores = ppr_scores_[s][nt]; - int32_t k = std::min(max_ppr_nodes, static_cast(scores.size())); + for (int32_t s = 0; s < _batchSize; ++s) { + const auto& scores = _pprScores[s][nt]; + int32_t k = std::min(maxPprNodes, static_cast(scores.size())); if (k > 0) { std::vector> items(scores.begin(), scores.end()); std::partial_sort(items.begin(), items.begin() + k, items.end(), [](const auto& a, const auto& b) { @@ -238,36 +250,38 @@ std::unordered_map(items[i].first)); + flatIds.push_back(static_cast(items[i].first)); // Cast to float32 for output; internal scores stay double to // avoid accumulated rounding errors in the push loop. - flat_weights.push_back(static_cast(items[i].second)); + flatWeights.push_back(static_cast(items[i].second)); } } - valid_counts.push_back(static_cast(k)); + validCounts.push_back(static_cast(k)); } - result[nt] = {torch::tensor(flat_ids, torch::kLong), - torch::tensor(flat_weights, torch::kFloat), - torch::tensor(valid_counts, torch::kLong)}; + result[nt] = {torch::tensor(flatIds, torch::kLong), + torch::tensor(flatWeights, torch::kFloat), + torch::tensor(validCounts, torch::kLong)}; } return result; } -int32_t PPRForwardPushState::get_total_degree(int32_t node_id, int32_t ntype_id) const { - if (ntype_id >= static_cast(degree_tensors_.size())) +int32_t PPRForwardPushState::getTotalDegree(int32_t nodeId, int32_t ntypeId) const { + if (ntypeId >= static_cast(_degreeTensors.size())) { return 0; - const auto& t = degree_tensors_[ntype_id]; - if (t.numel() == 0) + } + const auto& t = _degreeTensors[ntypeId]; + if (t.numel() == 0) { return 0; - TORCH_CHECK(node_id < static_cast(t.size(0)), + } + TORCH_CHECK(nodeId < static_cast(t.size(0)), "Node ID ", - node_id, + nodeId, " out of range for degree tensor of ntype_id ", - ntype_id, + ntypeId, " (size=", t.size(0), "). This indicates corrupted graph data or a sampler bug."); // data_ptr() returns a raw C pointer to the tensor's int32 data buffer. - return t.data_ptr()[node_id]; + return t.data_ptr()[nodeId]; } diff --git a/gigl/csrc/sampling/ppr_forward_push.h b/gigl/csrc/sampling/ppr_forward_push.h index 82973ff7a..7a6fac69d 100644 --- a/gigl/csrc/sampling/ppr_forward_push.h +++ b/gigl/csrc/sampling/ppr_forward_push.h @@ -22,9 +22,9 @@ // negative int32_t (e.g. -1 = 0xFFFFFFFF) would be sign-extended to a full // 64-bit value, corrupting the upper bits when shifted. Reinterpreting as // uint32_t first treats the bit pattern as-is (no sign extension). -static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { - return (static_cast(static_cast(node_id)) << 32) | - static_cast(etype_id); +static inline uint64_t packKey(int32_t nodeId, int32_t etypeId) { + return (static_cast(static_cast(nodeId)) << 32) | + static_cast(etypeId); } // C++ kernel for the PPR Forward Push algorithm (Andersen et al., 2006). @@ -33,43 +33,45 @@ static inline uint64_t pack_key(int32_t node_id, int32_t etype_id) { // this object. The distributed neighbor fetch is kept in Python because it // involves async RPC calls that C++ cannot drive directly. // -// Owned state: ppr_scores, residuals, queue, queued_nodes, neighbor_cache. +// Owned state: _pprScores, _residuals, _queue, _queuedNodes, _neighborCache. // Python retains ownership of: the distributed neighbor fetch (_batch_fetch_neighbors). // // Typical call sequence per batch: -// 1. PPRForwardPushState(seed_nodes, ...) — init per-seed residuals / queue +// 1. PPRForwardPushState(seedNodes, ...) — init per-seed residuals / queue // while True: -// 2. drain_queue() — drain queue → nodes needing lookup +// 2. drainQueue() — drain queue → nodes needing lookup // 3. — distributed RPC fetch (stays in Python) -// 4. push_residuals(fetched_by_etype_id) — push residuals, update queue -// 5. extract_top_k(max_ppr_nodes) — top-k selection per seed per node type +// 4. pushResiduals(fetchedByEtypeId) — push residuals, update queue +// 5. extractTopK(maxPprNodes) — top-k selection per seed per node type class PPRForwardPushState { public: - PPRForwardPushState(torch::Tensor seed_nodes, int32_t seed_node_type_id, double alpha, - double requeue_threshold_factor, - std::vector> node_type_to_edge_type_ids, - std::vector edge_type_to_dst_ntype_id, - std::vector degree_tensors); + PPRForwardPushState(const torch::Tensor& seedNodes, + int32_t seedNodeTypeId, + double alpha, + double requeueThresholdFactor, + std::vector> nodeTypeToEdgeTypeIds, + std::vector edgeTypeToDstNtypeId, + std::vector degreeTensors); // Drain all queued nodes and return {etype_id: tensor[node_ids]} for batch - // neighbor lookup. Also snapshots the drained nodes into queued_nodes_ for - // use by push_residuals(). + // neighbor lookup. Also snapshots the drained nodes into _queuedNodes for + // use by pushResiduals(). // // Return value semantics: // - std::nullopt → queue was already empty; convergence achieved; stop the loop. - // - empty map → nodes were drained but all were cached; call push_residuals({}). + // - empty map → nodes were drained but all were cached; call pushResiduals({}). // - non-empty map → {etype_id → 1-D int64 tensor of node IDs} needing neighbor lookup. - std::optional> drain_queue(); + std::optional> drainQueue(); // Push residuals to neighbors given the fetched neighbor data. // - // fetched_by_etype_id: {etype_id: (node_ids_tensor, flat_nbrs_tensor, counts_tensor)} + // fetchedByEtypeId: {etype_id: (node_ids_tensor, flat_nbrs_tensor, counts_tensor)} // - node_ids_tensor: [N] int64 — source node IDs fetched for this edge type // - flat_nbrs_tensor: [sum(counts)] int64 — all neighbor lists concatenated flat // - counts_tensor: [N] int64 — neighbor count for each source node - void push_residuals(const std::unordered_map< - int32_t, std::tuple>& - fetched_by_etype_id); + void pushResiduals(const std::unordered_map< + int32_t, std::tuple>& + fetchedByEtypeId); // Extract top-k PPR nodes per seed per node type. // @@ -81,52 +83,51 @@ class PPRForwardPushState { // flat_ids[valid_counts[0] : valid_counts[0]+valid_counts[1]] → top-k for seed 1 // ... std::unordered_map> - extract_top_k(int32_t max_ppr_nodes); + extractTopK(int32_t maxPprNodes); + + // Returns _nodesDrainedPerIteration built up across all drainQueue() calls. + [[nodiscard]] const std::vector& getNodesDrainedPerIteration() const; private: // Look up the total (across all edge types) out-degree of a node. // Returns 0 for destination-only node types (no outgoing edges). - int32_t get_total_degree(int32_t node_id, int32_t ntype_id) const; + [[nodiscard]] int32_t getTotalDegree(int32_t nodeId, int32_t ntypeId) const; // ------------------------------------------------------------------------- // Scalar algorithm parameters // ------------------------------------------------------------------------- - double alpha_; // Restart probability - double one_minus_alpha_; // 1 - alpha, precomputed to avoid repeated subtraction - double requeue_threshold_factor_; // alpha * eps; multiplied by degree to get per-node threshold + double _alpha; // Restart probability + double _oneMinusAlpha; // 1 - alpha, precomputed to avoid repeated subtraction + double _requeueThresholdFactor; // alpha * eps; multiplied by degree to get per-node threshold - int32_t batch_size_; // Number of seeds in the current batch - int32_t num_node_types_; // Total number of node types (homo + hetero) - int32_t num_nodes_in_queue_{0}; // Running count of nodes across all seeds / types + int32_t _batchSize; // Number of seeds in the current batch + int32_t _numNodeTypes; // Total number of node types (homo + hetero) + int32_t _numNodesInQueue{0}; // Running count of nodes across all seeds / types // ------------------------------------------------------------------------- // Graph structure (read-only after construction) // ------------------------------------------------------------------------- - std::vector> node_type_to_edge_type_ids_; - std::vector edge_type_to_dst_ntype_id_; - std::vector degree_tensors_; + std::vector> _nodeTypeToEdgeTypeIds; + std::vector _edgeTypeToDstNtypeId; + std::vector _degreeTensors; // ------------------------------------------------------------------------- // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]) // ------------------------------------------------------------------------- - std::vector>> ppr_scores_; - std::vector>> residuals_; - std::vector>> queue_; - std::vector>> queued_nodes_; + std::vector>> _pprScores; + std::vector>> _residuals; + std::vector>> _queue; + std::vector>> _queuedNodes; // ------------------------------------------------------------------------- // Neighbor cache // ------------------------------------------------------------------------- - std::unordered_map> neighbor_cache_; + std::unordered_map> _neighborCache; // ------------------------------------------------------------------------- // Diagnostics (populated during the algorithm; read after convergence) // ------------------------------------------------------------------------- - // Total nodes drained (across all seeds and node types) in each drain_queue() + // Total nodes drained (across all seeds and node types) in each drainQueue() // call. One entry per loop iteration; useful for understanding convergence speed. - std::vector nodes_drained_per_iteration_; - - public: - // Returns nodes_drained_per_iteration_ built up across all drain_queue() calls. - const std::vector& get_nodes_drained_per_iteration() const; + std::vector _nodesDrainedPerIteration; }; diff --git a/gigl/csrc/sampling/python_ppr_forward_push.cpp b/gigl/csrc/sampling/python_ppr_forward_push.cpp index aafb32cdc..98ff40179 100644 --- a/gigl/csrc/sampling/python_ppr_forward_push.cpp +++ b/gigl/csrc/sampling/python_ppr_forward_push.cpp @@ -11,10 +11,10 @@ namespace py = pybind11; -// drain_queue: C++ returns std::optional>. +// drainQueue: C++ returns std::optional>. // Exposed to Python as: None (convergence) or dict[int, Tensor]. -static py::object drain_queue_wrapper(PPRForwardPushState& self) { - auto result = self.drain_queue(); +static py::object drainQueueWrapper(PPRForwardPushState& self) { + auto result = self.drainQueue(); if (!result) { return py::none(); } @@ -25,29 +25,29 @@ static py::object drain_queue_wrapper(PPRForwardPushState& self) { return d; } -// push_residuals: Python passes dict[int, tuple[Tensor, Tensor, Tensor]]. +// pushResiduals: Python passes dict[int, tuple[Tensor, Tensor, Tensor]]. // Convert to C++ map before delegating. -static void push_residuals_wrapper(PPRForwardPushState& self, py::dict fetched_by_etype_id) { - std::unordered_map> cpp_map; +static void pushResidualsWrapper(PPRForwardPushState& self, const py::dict& fetchedByEtypeId) { + std::unordered_map> cppMap; // Dict iteration touches Python objects — GIL must be held here. - for (auto item : fetched_by_etype_id) { - int32_t eid = item.first.cast(); + for (auto item : fetchedByEtypeId) { + auto eid = item.first.cast(); auto tup = item.second.cast(); - cpp_map[eid] = {tup[0].cast(), tup[1].cast(), tup[2].cast()}; + cppMap[eid] = {tup[0].cast(), tup[1].cast(), tup[2].cast()}; } // C++ push only uses tensor accessor/data_ptr APIs — GIL-safe to release. // Releasing here lets the asyncio event loop process RPC completion callbacks // from other concurrent PPR coroutines while this push runs. { py::gil_scoped_release release; - self.push_residuals(cpp_map); + self.pushResiduals(cppMap); } } -// extract_top_k: C++ returns map>. +// extractTopK: C++ returns map>. // Exposed to Python as dict[int, tuple[Tensor, Tensor, Tensor]]. -static py::dict extract_top_k_wrapper(PPRForwardPushState& self, int32_t max_ppr_nodes) { - auto result = self.extract_top_k(max_ppr_nodes); +static py::dict extractTopKWrapper(PPRForwardPushState& self, int32_t maxPprNodes) { + auto result = self.extractTopK(maxPprNodes); py::dict d; for (auto& [nt, tup] : result) { d[py::int_(nt)] = py::make_tuple(std::get<0>(tup), std::get<1>(tup), std::get<2>(tup)); @@ -66,8 +66,8 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { std::vector>, std::vector, std::vector>()) - .def("drain_queue", drain_queue_wrapper) - .def("push_residuals", push_residuals_wrapper) - .def("extract_top_k", extract_top_k_wrapper) - .def("get_nodes_drained_per_iteration", &PPRForwardPushState::get_nodes_drained_per_iteration); + .def("drain_queue", drainQueueWrapper) + .def("push_residuals", pushResidualsWrapper) + .def("extract_top_k", extractTopKWrapper) + .def("get_nodes_drained_per_iteration", &PPRForwardPushState::getNodesDrainedPerIteration); } From 83e51bcd7285a69f100f88bc8154a59bce453a18 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 14 Apr 2026 00:05:57 +0000 Subject: [PATCH 038/148] Update --- .clang-tidy | 19 +++- Makefile | 4 +- docs/cpp_style_guide.md | 31 +++--- gigl/cpp_build_constants.py | 26 ----- requirements/install_cpp_deps.sh | 3 +- scripts/build_cpp_extensions.py | 18 +++- scripts/generate_compile_commands.py | 60 ----------- scripts/run_cpp_lint.py | 143 +++++++++++++++++++++++++++ 8 files changed, 192 insertions(+), 112 deletions(-) delete mode 100644 gigl/cpp_build_constants.py delete mode 100644 scripts/generate_compile_commands.py create mode 100644 scripts/run_cpp_lint.py diff --git a/.clang-tidy b/.clang-tidy index 3198f4627..39271bca7 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,16 +3,13 @@ Checks: > boost-use-to-string, bugprone-*, -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, -bugprone-narrowing-conversions, cert-err34-c, cert-flp30-c, cert-msc32-c, cert-msc50-cpp, cert-msc51-cpp, - clang-analyzer-*, - -clang-analyzer-alpha*, - -clang-analyzer-cplusplus.NewDeleteLeaks, - -clang-analyzer-osx*, clang-diagnostic-*, cppcoreguidelines-interfaces-global-init, cppcoreguidelines-no-malloc, @@ -27,17 +24,29 @@ Checks: > google-runtime-memset, hicpp-exception-baseclass, misc-*, + -misc-confusable-identifiers, + -misc-const-correctness, -misc-no-recursion, modernize-*, -modernize-avoid-c-arrays, + -modernize-use-trailing-return-type, performance-*, readability-*, + -readability-avoid-const-params-in-decls, + -readability-function-cognitive-complexity, -readability-container-contains, -readability-identifier-length, -readability-magic-numbers, +# WarningsAsErrors and HeaderFilterRegex work together: +# HeaderFilterRegex scopes which headers clang-tidy reports diagnostics for. +# Warnings from headers outside the regex (PyTorch, pybind11, etc.) are suppressed +# entirely and never reach WarningsAsErrors — so the large warning counts printed +# by clang-tidy ("N warnings generated") are third-party noise that is silently +# dropped. Only diagnostics in our own headers (.*/gigl/csrc/.*) are reported, +# and those are treated as hard errors. WarningsAsErrors: '*' -HeaderFilterRegex: '.*' +HeaderFilterRegex: '.*/gigl/csrc/.*' FormatStyle: none User: jenkins # CheckOptions: per-check tuning parameters. Each entry configures a specific diff --git a/Makefile b/Makefile index 79e2a02ba..90972ee1c 100644 --- a/Makefile +++ b/Makefile @@ -160,13 +160,13 @@ format: format_py format_cpp format_scala format_md type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs + $(MAKE) --no-print-directory lint_cpp build_cpp_extensions: uv run --no-sync python scripts/build_cpp_extensions.py build_ext --inplace lint_cpp: - uv run python scripts/generate_compile_commands.py - clang-tidy -p build/compile_commands.json $(CPP_SOURCES) + $(if $(CPP_SOURCES), uv run python scripts/run_cpp_lint.py $(CPP_SOURCES)) lint_test: check_format assert_yaml_configs_parse lint_cpp @echo "Lint checks pass!" diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 8fc84296e..a23ea6578 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -97,8 +97,7 @@ Enabled families: | `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | | `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | | `cert-*` | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | -| `clang-analyzer-*` | Clang static analyzer: memory safety, null dereferences, use-after-free, etc. | -| `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks | +| `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks (e.g. `-Wall`, `-Wextra` violations) | | `cppcoreguidelines-*` | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | | `google-*` | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | | `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | @@ -112,17 +111,21 @@ Enabled families: Some checks in the above families are disabled where they produce excessive noise or conflict with common patterns in this codebase: -| Disabled check | Reason | -| ----------------------------------------- | ----------------------------------------------------------------------------------- | -| `bugprone-easily-swappable-parameters` | Tensor and sampler APIs legitimately have many adjacent same-typed parameters | -| `bugprone-narrowing-conversions` | Too noisy in ML code mixing `int`/`int64_t`/`size_t` for tensor dimensions | -| `clang-analyzer-alpha*` | Alpha checks are experimental and unstable | -| `clang-analyzer-cplusplus.NewDeleteLeaks` | Ownership is managed via smart pointers; raw-new leaks are already caught elsewhere | -| `misc-no-recursion` | Recursive graph algorithms are intentional | -| `modernize-avoid-c-arrays` | C arrays are needed for pybind11 and C-interop code | -| `readability-container-contains` | `.contains()` requires C++20; the codebase builds with C++17 | -| `readability-identifier-length` | Short loop variables (`i`, `j`, `k`) are idiomatic | -| `readability-magic-numbers` | Literal constants are common in ML code (e.g. feature dimensions) | +| Disabled check | Reason | +| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `bugprone-easily-swappable-parameters` | Tensor and sampler APIs legitimately have many adjacent same-typed parameters | +| `bugprone-implicit-widening-of-multiplication-result` | Crashes clang-tidy 15 on a construct in `ATen/core/dynamic_type.h` (upstream LLVM bug). Re-enable when upgrading past clang-tidy 15. | +| `bugprone-narrowing-conversions` | Too noisy in ML code mixing `int`/`int64_t`/`size_t` for tensor dimensions | +| `misc-confusable-identifiers` | Performs an O(n²) comparison of all identifiers in scope to detect Unicode homoglyphs. PyTorch headers introduce thousands of identifiers, making this check account for ~70% of total lint time. All identifiers in this codebase are standard ASCII. | +| `misc-const-correctness` | Produces false positives with pybind11 types whose mutation happens through `operator[]` (which is non-const). The check incorrectly suggests `const` on variables that are mutated. | +| `misc-no-recursion` | Recursive graph algorithms are intentional | +| `modernize-avoid-c-arrays` | C arrays are needed for pybind11 and C-interop code | +| `modernize-use-trailing-return-type` | Trailing return types (`auto f() -> T`) are only useful when the return type depends on template params. Requiring them everywhere is non-standard and reduces readability. | +| `readability-avoid-const-params-in-decls` | Incorrectly fires on `const T&` parameters in multi-line declarations (clang-tidy 15 bug). The check is meant for top-level const on by-value params, which is a separate, valid concern. | +| `readability-container-contains` | `.contains()` requires C++20; the codebase builds with C++17 | +| `readability-identifier-length` | Short loop variables (`i`, `j`, `k`) are idiomatic | +| `readability-function-cognitive-complexity` | Algorithmic code often requires nesting that is inherent to the problem structure. Enforcing an arbitrary complexity ceiling discourages clarity and encourages artificial decomposition. | +| `readability-magic-numbers` | Literal constants are common in ML code (e.g. feature dimensions) | ### Naming conventions @@ -142,7 +145,7 @@ Enforced via `readability-identifier-naming`: | Option | Value | Effect | | ---------------------------------------------------------- | ---------------- | -------------------------------------------------------------- | | `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | -| `HeaderFilterRegex` | `.*` | Checks apply to all headers, not just implementation files | +| `HeaderFilterRegex` | `.*/gigl/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | | `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | | `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | | `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | diff --git a/gigl/cpp_build_constants.py b/gigl/cpp_build_constants.py deleted file mode 100644 index b638eb8f6..000000000 --- a/gigl/cpp_build_constants.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Shared C++ build constants for build_cpp_extensions.py and generate_compile_commands.py. - -This is the single source of truth for C++ compiler flags and source paths. -Both scripts import from here so clang-tidy always analyzes with the same flags -used during the actual build. -""" - -from pathlib import Path - -# REPO_ROOT is derived from this file's location — this file must live in gigl/. -REPO_ROOT: Path = Path(__file__).resolve().parent.parent -CSRC_DIR: Path = REPO_ROOT / "gigl" / "csrc" - -# Flags passed to every C++ compilation unit. Applies to both the extension -# build (build_cpp_extensions.py) and the compile_commands.json used by -# clang-tidy (generate_compile_commands.py). -# -Wno-unused-parameter suppresses noise from third-party headers (e.g. PyTorch) -# that don't compile cleanly under -Wextra. Unused parameters in our own code -# are still caught by clang-tidy's bugprone-* checks. -COMPILE_ARGS: list[str] = [ - "-O3", - "-std=c++17", - "-Wall", - "-Wextra", - "-Wno-unused-parameter", -] diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 796f34aef..25570eab8 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -46,9 +46,10 @@ else # into /usr/bin. update-alternatives wires up the bare names (clang-format, # clang-tidy) so callers don't need to specify the version suffix. No PATH # changes are needed since /usr/bin is already on PATH. - apt-get install -y "clang-format-${CLANG_VERSION}" "clang-tidy-${CLANG_VERSION}" cmake + apt-get install -y "clang-format-${CLANG_VERSION}" "clang-tidy-${CLANG_VERSION}" "clangd-${CLANG_VERSION}" cmake update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-${CLANG_VERSION}" 100 update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-${CLANG_VERSION}" 100 + update-alternatives --install /usr/bin/clangd clangd "/usr/bin/clangd-${CLANG_VERSION}" 100 fi echo "Finished installing C++ tooling" diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index b63a20634..89d0f9f91 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -8,11 +8,21 @@ python build_cpp_extensions.py build_ext --inplace """ +from pathlib import Path + from setuptools import setup from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension -from gigl.cpp_build_constants import COMPILE_ARGS, CSRC_DIR +_REPO_ROOT: Path = Path(__file__).resolve().parent.parent +_CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" +_COMPILE_ARGS: list[str] = [ + "-O3", + "-std=c++17", + "-Wall", + "-Wextra", + "-Wno-unused-parameter", +] def find_cpp_extensions() -> list[Extension]: @@ -23,10 +33,10 @@ def find_cpp_extensions() -> list[Extension]: Returns an empty list if ``gigl/csrc/`` does not yet exist. """ - if not CSRC_DIR.exists(): + if not _CSRC_DIR.exists(): return [] extensions = [] - for cpp_file in sorted(CSRC_DIR.rglob("python_*.cpp")): + for cpp_file in sorted(_CSRC_DIR.rglob("python_*.cpp")): parts = list(cpp_file.with_suffix("").parts) parts[-1] = parts[-1].removeprefix("python_") module_name = ".".join(parts) @@ -38,7 +48,7 @@ def find_cpp_extensions() -> list[Extension]: CppExtension( name=module_name, sources=sources, - extra_compile_args=COMPILE_ARGS, + extra_compile_args=_COMPILE_ARGS, ) ) return extensions diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py deleted file mode 100644 index f6bdad0bb..000000000 --- a/scripts/generate_compile_commands.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Generate build/compile_commands.json for clang-tidy analysis of GiGL C++ extensions. - -clang-tidy needs a compilation database to resolve include paths and compiler flags. -This script derives those paths directly from the installed torch and pybind11 packages, -avoiding the need for `bear` or a separate CMake build of the extension. - -Usage:: - - uv run python scripts/generate_compile_commands.py - -Output: ``build/compile_commands.json`` (created or overwritten). - -Note: run ``make build_cpp_extensions`` before this script (or use ``make lint_cpp``, -which does both in the correct order) so the database reflects the current build state. -""" - -import json -import sys -import sysconfig - -from torch.utils.cpp_extension import include_paths as torch_include_paths - -from gigl.cpp_build_constants import COMPILE_ARGS, CSRC_DIR, REPO_ROOT - - -def main() -> None: - # Collect all include directories needed to compile the extension. - # torch_include_paths() returns the torch headers, which already bundle - # pybind11 under torch/include/pybind11/ — no separate pybind11 import needed. - include_flags: list[str] = [f"-I{path}" for path in torch_include_paths()] - # Python C API headers (e.g. Python.h) required by pybind11. - include_flags.append(f"-I{sysconfig.get_path('include')}") - - cpp_sources = sorted(CSRC_DIR.rglob("*.cpp")) if CSRC_DIR.exists() else [] - if not cpp_sources: - print(f"Warning: no .cpp files found under {CSRC_DIR}", file=sys.stderr) - - cxx_flags = " ".join(COMPILE_ARGS) - - # Each entry in compile_commands.json describes how one source file is compiled. - # clang-tidy reads this to reproduce the exact compilation environment. - commands: list[dict[str, str]] = [ - { - "directory": str(REPO_ROOT), - "file": str(source), - "command": f"c++ {cxx_flags} {' '.join(include_flags)} -c {source}", - } - for source in cpp_sources - ] - - output = REPO_ROOT / "build" / "compile_commands.json" - output.parent.mkdir(exist_ok=True) - output.write_text(json.dumps(commands, indent=2)) - print( - f"Wrote {len(commands)} entr{'y' if len(commands) == 1 else 'ies'} to {output}" - ) - - -if __name__ == "__main__": - main() diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py new file mode 100644 index 000000000..15eaa938c --- /dev/null +++ b/scripts/run_cpp_lint.py @@ -0,0 +1,143 @@ +"""Run C++ lint on source files using clangd. + +Generates compile_commands.json, then runs clangd --check on each file in +parallel and prints a clean summary. + +Usage:: + + # Lint specific files (also regenerates compile_commands.json): + uv run python scripts/run_cpp_lint.py [file2.cpp] ... + + # Regenerate build/compile_commands.json only (for IDE / clangd setup): + uv run python scripts/run_cpp_lint.py +""" + +import json +import re +import subprocess +import sys +import sysconfig +import warnings +from concurrent.futures import ThreadPoolExecutor, as_completed +from pathlib import Path + +_REPO_ROOT: Path = Path(__file__).resolve().parent.parent +_CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" +_COMPILE_COMMANDS: Path = _REPO_ROOT / "build" / "compile_commands.json" +_COMPILE_ARGS: list[str] = [ + "-O3", + "-std=c++17", + "-Wall", + "-Wextra", + "-Wno-unused-parameter", +] + +# Matches real clang-tidy diagnostics emitted by clangd: +# E[HH:MM:SS.mmm] [check-name] Line N: message +_DIAGNOSTIC_RE = re.compile(r"^E\[[\d:.]+\] (\[.+\] .+)$") + + +def _get_cxx_system_include_flags() -> list[str]: + """Return -isystem flags for C++ standard library headers. + + clang++-15 on some machines is not configured with the correct GCC toolchain + path and cannot find standard headers on its own. We derive them from the + system g++ and pass them explicitly. + """ + try: + result = subprocess.run( + ["c++", "-v", "-x", "c++", "-E", "/dev/null"], + capture_output=True, + text=True, + ) + includes: list[str] = [] + in_section = False + for line in result.stderr.splitlines(): + if "#include <...> search starts here:" in line: + in_section = True + continue + if "End of search list." in line: + break + if in_section and line.strip(): + includes.append(f"-isystem{line.strip()}") + return includes + except FileNotFoundError: + return [] + + +def _generate_compile_commands() -> None: + """Write build/compile_commands.json for clangd.""" + # Suppress PyTorch's CUDA-not-found warning emitted at import time. + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + from torch.utils.cpp_extension import include_paths as torch_include_paths + + # -isystem (not -I) marks these as system headers so clangd's checks skip + # AST nodes originating from them, avoiding deep analysis of PyTorch internals. + include_flags: list[str] = [f"-isystem{p}" for p in torch_include_paths()] + include_flags.append(f"-isystem{sysconfig.get_path('include')}") + include_flags.extend(_get_cxx_system_include_flags()) + + cpp_sources = sorted(_CSRC_DIR.rglob("*.cpp")) if _CSRC_DIR.exists() else [] + cxx_flags = " ".join(_COMPILE_ARGS) + + commands = [ + { + "directory": str(_REPO_ROOT), + "file": str(source), + "command": f"clang++-15 {cxx_flags} {' '.join(include_flags)} -c {source}", + } + for source in cpp_sources + ] + + _COMPILE_COMMANDS.parent.mkdir(exist_ok=True) + _COMPILE_COMMANDS.write_text(json.dumps(commands, indent=2)) + + +def _check_file(source: Path) -> tuple[Path, list[str]]: + result = subprocess.run( + [ + "clangd", + f"--check={source}", + f"--compile-commands-dir={_COMPILE_COMMANDS.parent}", + ], + capture_output=True, + text=True, + ) + diagnostics: list[str] = [] + for line in result.stderr.splitlines(): + m = _DIAGNOSTIC_RE.match(line) + if m: + diagnostics.append(m.group(1)) + return source, diagnostics + + +def main() -> None: + sources = [Path(s) for s in sys.argv[1:]] + + _generate_compile_commands() + + if not sources: + print(f"Wrote {_COMPILE_COMMANDS}") + return + + failures: dict[Path, list[str]] = {} + with ThreadPoolExecutor() as executor: + futures = {executor.submit(_check_file, s): s for s in sources} + for future in as_completed(futures): + source, diagnostics = future.result() + if diagnostics: + failures[source] = diagnostics + + if not failures: + print("\033[32mC++ lint passed.\033[0m") + else: + for source in sorted(failures): + print(f" FAIL {source}") + for d in failures[source]: + print(f" {d}") + sys.exit(1) + + +if __name__ == "__main__": + main() From 5e55f54e8c09011887f8feb92499e5b16c422382 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 16 Apr 2026 18:26:15 +0000 Subject: [PATCH 039/148] Updaate --- Makefile | 12 ++- docs/cpp_style_guide.md | 74 +++++++++---------- scripts/generate_compile_commands.py | 105 +++++++++++++++++++++++++++ scripts/run_cpp_lint.py | 83 +-------------------- 4 files changed, 156 insertions(+), 118 deletions(-) create mode 100644 scripts/generate_compile_commands.py diff --git a/Makefile b/Makefile index 90972ee1c..66d4afb01 100644 --- a/Makefile +++ b/Makefile @@ -160,13 +160,21 @@ format: format_py format_cpp format_scala format_md type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs - $(MAKE) --no-print-directory lint_cpp build_cpp_extensions: uv run --no-sync python scripts/build_cpp_extensions.py build_ext --inplace +generate_compile_commands: + uv run python -m scripts.generate_compile_commands + lint_cpp: - $(if $(CPP_SOURCES), uv run python scripts/run_cpp_lint.py $(CPP_SOURCES)) + $(if $(CPP_SOURCES), uv run python -m scripts.run_cpp_lint $(CPP_SOURCES)) + +# Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, +# changes expressions, adds/removes keywords), not just style. Run manually and +# review the diff before committing. +fix_cpp_lint: generate_compile_commands + $(if $(CPP_SOURCES), clang-tidy --fix -p build/compile_commands.json $(CPP_SOURCES)) lint_test: check_format assert_yaml_configs_parse lint_cpp @echo "Lint checks pass!" diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index a23ea6578..cadac0e28 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -92,40 +92,40 @@ warnings are errors — there is no "warning-only" category. Enabled families: -| Family | What it covers | -| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | -| `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | -| `cert-*` | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | -| `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks (e.g. `-Wall`, `-Wextra` violations) | -| `cppcoreguidelines-*` | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | -| `google-*` | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | -| `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | -| `misc-*` | Miscellaneous: header-only definitions, suspicious enum usage, throw-by-value/catch-by-reference, etc. | -| `modernize-*` | Modernize to C++11/14/17: `nullptr`, range-based for, `make_unique`, `using` aliases, etc. | -| `performance-*` | Unnecessary copies, inefficient string ops, missed `emplace`, type promotions in math functions | -| `readability-*` | Naming conventions, braces around statements, boolean simplification, function size limits | +| Family | What it covers | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `boost-use-to-string` | Prefer `std::to_string` over `boost::lexical_cast` for numeric conversions | +| `bugprone-*` | Common programming mistakes: dangling handles, suspicious string construction, assert side effects, etc. | +| `cert-*` | CERT secure coding rules for error handling (`err34-c`), floating-point loops (`flp30-c`), and RNG seeding (`msc32-c`, `msc50/51-cpp`) | +| `clang-diagnostic-*` | Compiler diagnostic warnings surfaced as lint checks (e.g. `-Wall`, `-Wextra` violations) | +| `cppcoreguidelines-*` | C++ Core Guidelines: no raw `malloc`, no union member access, no object slicing, safe downcasts | +| `google-*` | Google C++ style: explicit constructors, no global names in headers, safe `memset` usage | +| `hicpp-exception-baseclass` | All thrown exceptions must derive from `std::exception` | +| `misc-*` | Miscellaneous: header-only definitions, suspicious enum usage, throw-by-value/catch-by-reference, etc. | +| `modernize-*` | Modernize to C++11/14/17: `nullptr`, range-based for, `make_unique`, `using` aliases, etc. | +| `performance-*` | Unnecessary copies, inefficient string ops, missed `emplace`, type promotions in math functions | +| `readability-*` | Naming conventions, braces around statements, boolean simplification, function size limits | ### Disabled checks Some checks in the above families are disabled where they produce excessive noise or conflict with common patterns in this codebase: -| Disabled check | Reason | -| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `bugprone-easily-swappable-parameters` | Tensor and sampler APIs legitimately have many adjacent same-typed parameters | -| `bugprone-implicit-widening-of-multiplication-result` | Crashes clang-tidy 15 on a construct in `ATen/core/dynamic_type.h` (upstream LLVM bug). Re-enable when upgrading past clang-tidy 15. | -| `bugprone-narrowing-conversions` | Too noisy in ML code mixing `int`/`int64_t`/`size_t` for tensor dimensions | -| `misc-confusable-identifiers` | Performs an O(n²) comparison of all identifiers in scope to detect Unicode homoglyphs. PyTorch headers introduce thousands of identifiers, making this check account for ~70% of total lint time. All identifiers in this codebase are standard ASCII. | -| `misc-const-correctness` | Produces false positives with pybind11 types whose mutation happens through `operator[]` (which is non-const). The check incorrectly suggests `const` on variables that are mutated. | -| `misc-no-recursion` | Recursive graph algorithms are intentional | -| `modernize-avoid-c-arrays` | C arrays are needed for pybind11 and C-interop code | -| `modernize-use-trailing-return-type` | Trailing return types (`auto f() -> T`) are only useful when the return type depends on template params. Requiring them everywhere is non-standard and reduces readability. | -| `readability-avoid-const-params-in-decls` | Incorrectly fires on `const T&` parameters in multi-line declarations (clang-tidy 15 bug). The check is meant for top-level const on by-value params, which is a separate, valid concern. | -| `readability-container-contains` | `.contains()` requires C++20; the codebase builds with C++17 | -| `readability-identifier-length` | Short loop variables (`i`, `j`, `k`) are idiomatic | -| `readability-function-cognitive-complexity` | Algorithmic code often requires nesting that is inherent to the problem structure. Enforcing an arbitrary complexity ceiling discourages clarity and encourages artificial decomposition. | -| `readability-magic-numbers` | Literal constants are common in ML code (e.g. feature dimensions) | +| Disabled check | Reason | +| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `bugprone-easily-swappable-parameters` | Tensor and sampler APIs legitimately have many adjacent same-typed parameters | +| `bugprone-implicit-widening-of-multiplication-result` | Crashes clang-tidy 15 on a construct in `ATen/core/dynamic_type.h` (upstream LLVM bug). Re-enable when upgrading past clang-tidy 15. | +| `bugprone-narrowing-conversions` | Too noisy in ML code mixing `int`/`int64_t`/`size_t` for tensor dimensions | +| `misc-confusable-identifiers` | Performs an O(n²) comparison of all identifiers in scope to detect Unicode homoglyphs. PyTorch headers introduce thousands of identifiers, making this check account for ~70% of total lint time. All identifiers in this codebase are standard ASCII. | +| `misc-const-correctness` | Produces false positives with pybind11 types whose mutation happens through `operator[]` (which is non-const). The check incorrectly suggests `const` on variables that are mutated. | +| `misc-no-recursion` | Recursive graph algorithms are intentional | +| `modernize-avoid-c-arrays` | C arrays are needed for pybind11 and C-interop code | +| `modernize-use-trailing-return-type` | Trailing return types (`auto f() -> T`) are only useful when the return type depends on template params. Requiring them everywhere is non-standard and reduces readability. | +| `readability-avoid-const-params-in-decls` | Incorrectly fires on `const T&` parameters in multi-line declarations (clang-tidy 15 bug). The check is meant for top-level const on by-value params, which is a separate, valid concern. | +| `readability-container-contains` | `.contains()` requires C++20; the codebase builds with C++17 | +| `readability-identifier-length` | Short loop variables (`i`, `j`, `k`) are idiomatic | +| `readability-function-cognitive-complexity` | Algorithmic code often requires nesting that is inherent to the problem structure. Enforcing an arbitrary complexity ceiling discourages clarity and encourages artificial decomposition. | +| `readability-magic-numbers` | Literal constants are common in ML code (e.g. feature dimensions) | ### Naming conventions @@ -142,12 +142,12 @@ Enforced via `readability-identifier-naming`: ### Key option tuning -| Option | Value | Effect | -| ---------------------------------------------------------- | ---------------- | -------------------------------------------------------------- | -| `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | -| `HeaderFilterRegex` | `.*/gigl/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | -| `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | -| `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | -| `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | -| `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | -| `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | +| Option | Value | Effect | +| ---------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | +| `HeaderFilterRegex` | `.*/gigl/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | +| `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | +| `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | +| `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | +| `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | +| `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py new file mode 100644 index 000000000..8d27c7877 --- /dev/null +++ b/scripts/generate_compile_commands.py @@ -0,0 +1,105 @@ +"""Generate build/compile_commands.json for clangd IDE integration. + +clangd needs a compilation database to resolve include paths and compiler flags. +This script derives those paths from the installed torch and pybind11 packages. + +This script is for IDE setup (VS Code, CLion, etc.) and is also called by +``run_cpp_lint.py`` before running clangd checks. + +Usage:: + + uv run python scripts/generate_compile_commands.py + +Output: ``build/compile_commands.json`` (created or overwritten). +""" + +import json +import subprocess +import sys +import sysconfig +import warnings +from pathlib import Path + +_REPO_ROOT: Path = Path(__file__).resolve().parent.parent +_CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" +_COMPILE_COMMANDS: Path = _REPO_ROOT / "build" / "compile_commands.json" +_COMPILE_ARGS: list[str] = [ + "-O3", + "-std=c++17", + "-Wall", + "-Wextra", + "-Wno-unused-parameter", +] + + +def _get_cxx_system_include_flags() -> list[str]: + """Return -isystem flags for the C++ standard library headers. + + clang++-15 on some machines is not configured with the correct GCC toolchain + path, so it cannot find standard headers like on its own. We ask + the system g++ compiler for its include search paths and pass them explicitly, + which is the reliable cross-machine approach. + """ + try: + result = subprocess.run( + ["c++", "-v", "-x", "c++", "-E", "/dev/null"], + capture_output=True, + text=True, + ) + includes: list[str] = [] + in_section = False + for line in result.stderr.splitlines(): + if "#include <...> search starts here:" in line: + in_section = True + continue + if "End of search list." in line: + break + if in_section and line.strip(): + includes.append(f"-isystem{line.strip()}") + return includes + except FileNotFoundError: + print( + "Warning: 'c++' not found; C++ system headers will be missing", + file=sys.stderr, + ) + return [] + + +def generate() -> None: + """Write build/compile_commands.json for clangd.""" + # Suppress PyTorch's CUDA-not-found warning emitted at import time. + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + from torch.utils.cpp_extension import include_paths as torch_include_paths + + # -isystem marks these as system headers so clangd skips deep analysis of + # PyTorch internals. + include_flags: list[str] = [f"-isystem{p}" for p in torch_include_paths()] + include_flags.append(f"-isystem{sysconfig.get_path('include')}") + include_flags.extend(_get_cxx_system_include_flags()) + + cpp_sources = sorted(_CSRC_DIR.rglob("*.cpp")) if _CSRC_DIR.exists() else [] + if not cpp_sources: + print(f"Warning: no .cpp files found under {_CSRC_DIR}", file=sys.stderr) + + cxx_flags = " ".join(_COMPILE_ARGS) + commands: list[dict[str, str]] = [ + { + "directory": str(_REPO_ROOT), + "file": str(source), + "command": f"clang++-15 {cxx_flags} {' '.join(include_flags)} -c {source}", + } + for source in cpp_sources + ] + + _COMPILE_COMMANDS.parent.mkdir(exist_ok=True) + _COMPILE_COMMANDS.write_text(json.dumps(commands, indent=2)) + + +def main() -> None: + generate() + print(f"Wrote {_COMPILE_COMMANDS}") + + +if __name__ == "__main__": + main() diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 15eaa938c..dcf13e8b5 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -5,95 +5,22 @@ Usage:: - # Lint specific files (also regenerates compile_commands.json): uv run python scripts/run_cpp_lint.py [file2.cpp] ... - - # Regenerate build/compile_commands.json only (for IDE / clangd setup): - uv run python scripts/run_cpp_lint.py """ -import json import re import subprocess import sys -import sysconfig -import warnings from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path -_REPO_ROOT: Path = Path(__file__).resolve().parent.parent -_CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" -_COMPILE_COMMANDS: Path = _REPO_ROOT / "build" / "compile_commands.json" -_COMPILE_ARGS: list[str] = [ - "-O3", - "-std=c++17", - "-Wall", - "-Wextra", - "-Wno-unused-parameter", -] +from scripts.generate_compile_commands import _COMPILE_COMMANDS, generate # Matches real clang-tidy diagnostics emitted by clangd: # E[HH:MM:SS.mmm] [check-name] Line N: message _DIAGNOSTIC_RE = re.compile(r"^E\[[\d:.]+\] (\[.+\] .+)$") -def _get_cxx_system_include_flags() -> list[str]: - """Return -isystem flags for C++ standard library headers. - - clang++-15 on some machines is not configured with the correct GCC toolchain - path and cannot find standard headers on its own. We derive them from the - system g++ and pass them explicitly. - """ - try: - result = subprocess.run( - ["c++", "-v", "-x", "c++", "-E", "/dev/null"], - capture_output=True, - text=True, - ) - includes: list[str] = [] - in_section = False - for line in result.stderr.splitlines(): - if "#include <...> search starts here:" in line: - in_section = True - continue - if "End of search list." in line: - break - if in_section and line.strip(): - includes.append(f"-isystem{line.strip()}") - return includes - except FileNotFoundError: - return [] - - -def _generate_compile_commands() -> None: - """Write build/compile_commands.json for clangd.""" - # Suppress PyTorch's CUDA-not-found warning emitted at import time. - with warnings.catch_warnings(): - warnings.filterwarnings("ignore") - from torch.utils.cpp_extension import include_paths as torch_include_paths - - # -isystem (not -I) marks these as system headers so clangd's checks skip - # AST nodes originating from them, avoiding deep analysis of PyTorch internals. - include_flags: list[str] = [f"-isystem{p}" for p in torch_include_paths()] - include_flags.append(f"-isystem{sysconfig.get_path('include')}") - include_flags.extend(_get_cxx_system_include_flags()) - - cpp_sources = sorted(_CSRC_DIR.rglob("*.cpp")) if _CSRC_DIR.exists() else [] - cxx_flags = " ".join(_COMPILE_ARGS) - - commands = [ - { - "directory": str(_REPO_ROOT), - "file": str(source), - "command": f"clang++-15 {cxx_flags} {' '.join(include_flags)} -c {source}", - } - for source in cpp_sources - ] - - _COMPILE_COMMANDS.parent.mkdir(exist_ok=True) - _COMPILE_COMMANDS.write_text(json.dumps(commands, indent=2)) - - def _check_file(source: Path) -> tuple[Path, list[str]]: result = subprocess.run( [ @@ -114,12 +41,10 @@ def _check_file(source: Path) -> tuple[Path, list[str]]: def main() -> None: sources = [Path(s) for s in sys.argv[1:]] - - _generate_compile_commands() - if not sources: - print(f"Wrote {_COMPILE_COMMANDS}") - return + sys.exit(0) + + generate() failures: dict[Path, list[str]] = {} with ThreadPoolExecutor() as executor: From 7b742f25fc4a72ce5ff9d6a8bbbf8c1aa3c4e63e Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 16 Apr 2026 19:04:56 +0000 Subject: [PATCH 040/148] Add C++ linting infrastructure with clangd - Switch from clang-tidy to clangd --check for ~10x faster lint - Add scripts/run_cpp_lint.py: parallel clangd checks with clean output - Add scripts/generate_compile_commands.py: standalone compile DB generation for IDE setup and as a dependency of fix_lint_cpp - Add scripts/_cpp_config.py: single source of truth for compile flags - Fix clang++-15 hardcode; use clang++ resolved via update-alternatives - Add fix_lint_cpp Makefile target for manual clang-tidy --fix runs - Move check_lint_cpp out of type_check and into lint_test where it belongs - Disable misc-confusable-identifiers (was 70% of lint time) and readability-function-cognitive-complexity in .clang-tidy --- Makefile | 8 +++---- docs/cpp_style_guide.md | 2 +- scripts/_cpp_config.py | 3 +++ scripts/build_cpp_extensions.py | 10 ++------- scripts/generate_compile_commands.py | 33 ++++++++++++---------------- scripts/run_cpp_lint.py | 4 ++-- 6 files changed, 26 insertions(+), 34 deletions(-) create mode 100644 scripts/_cpp_config.py diff --git a/Makefile b/Makefile index 66d4afb01..170ab45ba 100644 --- a/Makefile +++ b/Makefile @@ -162,21 +162,21 @@ type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs build_cpp_extensions: - uv run --no-sync python scripts/build_cpp_extensions.py build_ext --inplace + uv run --no-sync python -m scripts.build_cpp_extensions build_ext --inplace generate_compile_commands: uv run python -m scripts.generate_compile_commands -lint_cpp: +check_lint_cpp: $(if $(CPP_SOURCES), uv run python -m scripts.run_cpp_lint $(CPP_SOURCES)) # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, # changes expressions, adds/removes keywords), not just style. Run manually and # review the diff before committing. -fix_cpp_lint: generate_compile_commands +fix_lint_cpp: generate_compile_commands $(if $(CPP_SOURCES), clang-tidy --fix -p build/compile_commands.json $(CPP_SOURCES)) -lint_test: check_format assert_yaml_configs_parse lint_cpp +lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" # compiles current working state of scala projects to local jars diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index cadac0e28..33d3a2144 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -11,7 +11,7 @@ All clang-tidy warnings are treated as errors. ```bash make format_cpp # Format all C++ files in-place -make lint_cpp # Run clang-tidy static analysis +make check_lint_cpp # Run clang-tidy static analysis ``` ______________________________________________________________________ diff --git a/scripts/_cpp_config.py b/scripts/_cpp_config.py new file mode 100644 index 000000000..1ba53435e --- /dev/null +++ b/scripts/_cpp_config.py @@ -0,0 +1,3 @@ +"""Shared C++ build configuration used by build_cpp_extensions.py and generate_compile_commands.py.""" + +COMPILE_ARGS: list[str] = ["-O3", "-std=c++17", "-Wall", "-Wextra", "-Wno-unused-parameter"] diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index 89d0f9f91..d9559ce63 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -10,19 +10,13 @@ from pathlib import Path +from scripts._cpp_config import COMPILE_ARGS from setuptools import setup from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" -_COMPILE_ARGS: list[str] = [ - "-O3", - "-std=c++17", - "-Wall", - "-Wextra", - "-Wno-unused-parameter", -] def find_cpp_extensions() -> list[Extension]: @@ -48,7 +42,7 @@ def find_cpp_extensions() -> list[Extension]: CppExtension( name=module_name, sources=sources, - extra_compile_args=_COMPILE_ARGS, + extra_compile_args=COMPILE_ARGS, ) ) return extensions diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 8d27c7877..f6be10003 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -1,16 +1,16 @@ -"""Generate build/compile_commands.json for clangd IDE integration. +"""Generate build/compile_commands.json for clangd. -clangd needs a compilation database to resolve include paths and compiler flags. -This script derives those paths from the installed torch and pybind11 packages. +clangd requires a compilation database to resolve include paths and compiler +flags. This script derives those paths from the installed torch and pybind11 +packages and writes ``build/compile_commands.json``. -This script is for IDE setup (VS Code, CLion, etc.) and is also called by -``run_cpp_lint.py`` before running clangd checks. +Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and +by ``make generate_compile_commands`` when you need to refresh the database +manually (e.g. after adding new source files or changing compiler flags). Usage:: - uv run python scripts/generate_compile_commands.py - -Output: ``build/compile_commands.json`` (created or overwritten). + make generate_compile_commands """ import json @@ -20,16 +20,11 @@ import warnings from pathlib import Path +from scripts._cpp_config import COMPILE_ARGS + _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" _COMPILE_COMMANDS: Path = _REPO_ROOT / "build" / "compile_commands.json" -_COMPILE_ARGS: list[str] = [ - "-O3", - "-std=c++17", - "-Wall", - "-Wextra", - "-Wno-unused-parameter", -] def _get_cxx_system_include_flags() -> list[str]: @@ -65,7 +60,7 @@ def _get_cxx_system_include_flags() -> list[str]: return [] -def generate() -> None: +def write_compile_commands() -> None: """Write build/compile_commands.json for clangd.""" # Suppress PyTorch's CUDA-not-found warning emitted at import time. with warnings.catch_warnings(): @@ -82,12 +77,12 @@ def generate() -> None: if not cpp_sources: print(f"Warning: no .cpp files found under {_CSRC_DIR}", file=sys.stderr) - cxx_flags = " ".join(_COMPILE_ARGS) + cxx_flags = " ".join(COMPILE_ARGS) commands: list[dict[str, str]] = [ { "directory": str(_REPO_ROOT), "file": str(source), - "command": f"clang++-15 {cxx_flags} {' '.join(include_flags)} -c {source}", + "command": f"clang++ {cxx_flags} {' '.join(include_flags)} -c {source}", } for source in cpp_sources ] @@ -97,7 +92,7 @@ def generate() -> None: def main() -> None: - generate() + write_compile_commands() print(f"Wrote {_COMPILE_COMMANDS}") diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index dcf13e8b5..d3c19335d 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -14,7 +14,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path -from scripts.generate_compile_commands import _COMPILE_COMMANDS, generate +from scripts.generate_compile_commands import _COMPILE_COMMANDS, write_compile_commands # Matches real clang-tidy diagnostics emitted by clangd: # E[HH:MM:SS.mmm] [check-name] Line N: message @@ -44,7 +44,7 @@ def main() -> None: if not sources: sys.exit(0) - generate() + write_compile_commands() failures: dict[Path, list[str]] = {} with ThreadPoolExecutor() as executor: From 43c427148f1cea8e30a40af2761cd4aaf2d42b8d Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 16 Apr 2026 19:24:49 +0000 Subject: [PATCH 041/148] Update --- scripts/_cpp_config.py | 8 +++++++- scripts/build_cpp_extensions.py | 3 ++- scripts/run_cpp_lint.py | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/_cpp_config.py b/scripts/_cpp_config.py index 1ba53435e..e10ce1a0f 100644 --- a/scripts/_cpp_config.py +++ b/scripts/_cpp_config.py @@ -1,3 +1,9 @@ """Shared C++ build configuration used by build_cpp_extensions.py and generate_compile_commands.py.""" -COMPILE_ARGS: list[str] = ["-O3", "-std=c++17", "-Wall", "-Wextra", "-Wno-unused-parameter"] +COMPILE_ARGS: list[str] = [ + "-O3", + "-std=c++17", + "-Wall", + "-Wextra", + "-Wno-unused-parameter", +] diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index d9559ce63..42a983aa8 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -10,11 +10,12 @@ from pathlib import Path -from scripts._cpp_config import COMPILE_ARGS from setuptools import setup from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension +from scripts._cpp_config import COMPILE_ARGS + _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index d3c19335d..69c834fa0 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -61,6 +61,9 @@ def main() -> None: print(f" FAIL {source}") for d in failures[source]: print(f" {d}") + print( + "\nRun \033[1mmake fix_lint_cpp\033[0m to auto-fix violations where possible." + ) sys.exit(1) From d0859a393812da4a3920c7c4521f38bcd3bfcf72 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 16 Apr 2026 22:18:08 +0000 Subject: [PATCH 042/148] Update --- Makefile | 2 +- containers/Dockerfile.src | 2 +- gigl/scripts/post_install.py | 2 +- scripts/build_cpp_extensions.py | 3 +-- scripts/generate_compile_commands.py | 8 ++++---- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 170ab45ba..6129c85ec 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ check_lint_cpp: # changes expressions, adds/removes keywords), not just style. Run manually and # review the diff before committing. fix_lint_cpp: generate_compile_commands - $(if $(CPP_SOURCES), clang-tidy --fix -p build/compile_commands.json $(CPP_SOURCES)) + $(if $(CPP_SOURCES), clang-tidy --fix -p .cache/compile_commands.json $(CPP_SOURCES)) lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index 7b105084a..66ecf8599 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -21,4 +21,4 @@ COPY tests tests COPY examples examples RUN uv pip install -e . -RUN uv run python scripts/build_cpp_extensions.py build_ext --inplace +RUN uv run python -m scripts.build_cpp_extensions build_ext --inplace diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index bafc4ae21..563af1dc2 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -46,7 +46,7 @@ def main(): try: print("Building C++ extensions...") subprocess.run( - [sys.executable, str(build_cpp_script), "build_ext", "--inplace"], + [sys.executable, "-m", "scripts.build_cpp_extensions", "build_ext", "--inplace"], cwd=repo_root, check=True, ) diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index 42a983aa8..d9559ce63 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -10,12 +10,11 @@ from pathlib import Path +from scripts._cpp_config import COMPILE_ARGS from setuptools import setup from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension -from scripts._cpp_config import COMPILE_ARGS - _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index f6be10003..583112554 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -1,8 +1,8 @@ -"""Generate build/compile_commands.json for clangd. +"""Generate .cache/compile_commands.json for clangd. clangd requires a compilation database to resolve include paths and compiler flags. This script derives those paths from the installed torch and pybind11 -packages and writes ``build/compile_commands.json``. +packages and writes ``.cache/compile_commands.json``. Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and by ``make generate_compile_commands`` when you need to refresh the database @@ -24,7 +24,7 @@ _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" -_COMPILE_COMMANDS: Path = _REPO_ROOT / "build" / "compile_commands.json" +_COMPILE_COMMANDS: Path = _REPO_ROOT / ".cache" / "compile_commands.json" def _get_cxx_system_include_flags() -> list[str]: @@ -61,7 +61,7 @@ def _get_cxx_system_include_flags() -> list[str]: def write_compile_commands() -> None: - """Write build/compile_commands.json for clangd.""" + """Write .cache/compile_commands.json for clangd.""" # Suppress PyTorch's CUDA-not-found warning emitted at import time. with warnings.catch_warnings(): warnings.filterwarnings("ignore") From d07ca57e393b19868c28442db91eb8f2bb8388bb Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 16 Apr 2026 22:29:58 +0000 Subject: [PATCH 043/148] Update --- .../_cpp_config.py => gigl/csrc/cpp_compile_constants.py | 2 +- gigl/scripts/post_install.py | 8 +++++++- scripts/build_cpp_extensions.py | 3 ++- scripts/generate_compile_commands.py | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) rename scripts/_cpp_config.py => gigl/csrc/cpp_compile_constants.py (53%) diff --git a/scripts/_cpp_config.py b/gigl/csrc/cpp_compile_constants.py similarity index 53% rename from scripts/_cpp_config.py rename to gigl/csrc/cpp_compile_constants.py index e10ce1a0f..2b64d151b 100644 --- a/scripts/_cpp_config.py +++ b/gigl/csrc/cpp_compile_constants.py @@ -1,4 +1,4 @@ -"""Shared C++ build configuration used by build_cpp_extensions.py and generate_compile_commands.py.""" +"""C++ compiler flags used by the pybind11 extension build and clangd compile commands generation.""" COMPILE_ARGS: list[str] = [ "-O3", diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index 563af1dc2..15f1bab99 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -46,7 +46,13 @@ def main(): try: print("Building C++ extensions...") subprocess.run( - [sys.executable, "-m", "scripts.build_cpp_extensions", "build_ext", "--inplace"], + [ + sys.executable, + "-m", + "scripts.build_cpp_extensions", + "build_ext", + "--inplace", + ], cwd=repo_root, check=True, ) diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py index d9559ce63..85b5b13f2 100644 --- a/scripts/build_cpp_extensions.py +++ b/scripts/build_cpp_extensions.py @@ -10,11 +10,12 @@ from pathlib import Path -from scripts._cpp_config import COMPILE_ARGS from setuptools import setup from setuptools.extension import Extension from torch.utils.cpp_extension import BuildExtension, CppExtension +from gigl.csrc.cpp_compile_constants import COMPILE_ARGS + _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 583112554..e71d76933 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -20,7 +20,7 @@ import warnings from pathlib import Path -from scripts._cpp_config import COMPILE_ARGS +from gigl.csrc.cpp_compile_constants import COMPILE_ARGS _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" From 4815fae74aa110d4e469e39729183233f3b6921b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 16 Apr 2026 22:46:49 +0000 Subject: [PATCH 044/148] Update --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 6129c85ec..f627150b0 100644 --- a/Makefile +++ b/Makefile @@ -343,6 +343,7 @@ clean_build_files_scala: clean_build_files_cpp: rm -rf build/ + rm -f .cache/compile_commands.json clean_build_files: clean_build_files_py clean_build_files_scala clean_build_files_cpp From 912e5db63bb448d55a7de05020bab85d0265a0fc Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 16 Apr 2026 22:51:27 +0000 Subject: [PATCH 045/148] Update --- Makefile | 8 ++++---- tests/unit/cpp/CMakeLists.txt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index f627150b0..d20945f22 100644 --- a/Makefile +++ b/Makefile @@ -97,9 +97,9 @@ unit_test_scala: clean_build_files_scala # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. unit_test_cpp: - cmake -S tests/unit/cpp -B build/cpp_tests - cmake --build build/cpp_tests --parallel - ctest --test-dir build/cpp_tests --output-on-failure + cmake -S tests/unit/cpp -B .cache/cpp_tests + cmake --build .cache/cpp_tests --parallel + ctest --test-dir .cache/cpp_tests --output-on-failure unit_test: precondition_tests unit_test_py unit_test_scala unit_test_cpp @@ -342,7 +342,7 @@ clean_build_files_scala: ( cd scala_spark35; sbt clean; find . -type d -name "target" -prune -exec rm -rf {} \; ) clean_build_files_cpp: - rm -rf build/ + rm -rf .cache/cpp_tests rm -f .cache/compile_commands.json clean_build_files: clean_build_files_py clean_build_files_scala clean_build_files_cpp diff --git a/tests/unit/cpp/CMakeLists.txt b/tests/unit/cpp/CMakeLists.txt index 514625587..8b0ed16e7 100644 --- a/tests/unit/cpp/CMakeLists.txt +++ b/tests/unit/cpp/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include(FetchContent) FetchContent_Declare( googletest - URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz - URL_HASH SHA256=8372520bab45e12a97cd2f49dad36d07e55ddb89c0e39fad4a1a64cab0bdf35d + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.14.0 ) # Prevent GoogleTest from overriding the compiler's runtime on Windows # (no-op on Linux/Mac, but required for portable CMake config). From 5064788f16b140f26b0e1b2d7a673f5370f7b88e Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 17 Apr 2026 22:50:40 +0000 Subject: [PATCH 046/148] Address comments --- .github/workflows/release.yml | 22 ++++++- CMakeLists.txt | 60 +++++++++++++++++++ Makefile | 12 ++-- containers/Dockerfile.src | 2 +- gigl/csrc/cpp_compile_constants.py | 9 --- gigl/scripts/post_install.py | 35 +---------- pyproject.toml | 25 ++++++-- requirements/install_cpp_deps.sh | 25 ++++---- scripts/build_cpp_extensions.py | 55 ----------------- scripts/generate_compile_commands.py | 89 ++++++---------------------- scripts/run_cpp_lint.py | 2 +- 11 files changed, 138 insertions(+), 198 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 gigl/csrc/cpp_compile_constants.py delete mode 100644 scripts/build_cpp_extensions.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 777e68183..05bf649ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,8 +12,15 @@ permissions: jobs: build: - name: Build and release pip whl + name: Build and release pip whl (${{ matrix.torch-variant }}) runs-on: ubuntu-latest + strategy: + matrix: + include: + - torch-variant: cpu + torch-index: https://download.pytorch.org/whl/cpu + - torch-variant: cu128 + torch-index: https://download.pytorch.org/whl/cu128 env: PROJECT_ID: ${{ vars.GCP_PROJECT_ID }} environment: @@ -31,6 +38,7 @@ jobs: gcp_project_id: ${{ vars.GCP_PROJECT_ID }} workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} gcp_service_account_email: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + # We need build and twine to build the whl and upload it to Google Artifact Registry. # keyrings.google-artifactregistry-auth is needed to authenticate with Google Artifact Registry. # See: https://cloud.google.com/artifact-registry/docs/python/store-python @@ -40,8 +48,18 @@ jobs: # Pre-install keyring and Artifact Registry plugin from the public PyPI uv tool install keyring --with keyrings.google-artifactregistry-auth==1.1.2 + # install_dev_deps auto-detects CUDA and installs the CPU torch variant on + # ubuntu-latest runners. Override here with the correct variant for this build + # so CMake picks up the right torch headers (CPU-only vs CUDA-enabled). + - name: Install torch variant for build + run: | + uv pip install "torch==2.8" --index-url ${{ matrix.torch-index }} --inexact + + # Build without isolation so the pre-installed torch variant above is used. + # The build tag (e.g. 1cpu, 1cu128) differentiates the wheel filenames so + # both can coexist in the same registry index. - name: Build Whl Distribution - run: uv build + run: uv build --wheel --no-build-isolation -C "wheel.build-tag=1${{ matrix.torch-variant }}" - name: Publish Package 🚀 env: diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..51c492aba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.18) +project(gigl_csrc CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) +find_package(pybind11 CONFIG REQUIRED) + +# Locate PyTorch headers via its own cmake prefix path (works for both CPU and CUDA torch). +execute_process( + COMMAND "${Python_EXECUTABLE}" -c + "import torch; print(torch.utils.cmake_prefix_path)" + OUTPUT_VARIABLE TORCH_CMAKE_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# CUDA torch's CMake unconditionally calls enable_language(CUDA), which requires nvcc. +# nvcc may not be on PATH even when the CUDA toolkit is installed; find it explicitly. +if(NOT CMAKE_CUDA_COMPILER) + find_program(CMAKE_CUDA_COMPILER nvcc PATHS "/usr/local/cuda/bin") +endif() + +find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") + +set(GIGL_COMPILE_FLAGS -O3 -Wall -Wextra -Wno-unused-parameter) + +# --------------------------------------------------------------------------- +# Extension modules — auto-discovered. +# Files named python_*.cpp under gigl/csrc/ are compiled as pybind11 extension +# modules. The companion .cpp (without the "python_" prefix) is included +# automatically when present. This mirrors the convention from the old +# build_cpp_extensions.py: no changes here are needed to add new extensions. +# --------------------------------------------------------------------------- + +file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS + "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cpp" + "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cu" +) + +foreach(_py_src IN LISTS _PYTHON_SRCS) + get_filename_component(_dir "${_py_src}" DIRECTORY) + get_filename_component(_stem "${_py_src}" NAME_WE) + string(REGEX REPLACE "^python_" "" _name "${_stem}") + + set(_sources "${_py_src}") + foreach(_ext IN ITEMS cpp cu) + if(EXISTS "${_dir}/${_name}.${_ext}") + list(APPEND _sources "${_dir}/${_name}.${_ext}") + endif() + endforeach() + + file(RELATIVE_PATH _rel_dir "${CMAKE_SOURCE_DIR}" "${_dir}") + + pybind11_add_module("${_name}" ${_sources}) + target_link_libraries("${_name}" PRIVATE "${TORCH_LIBRARIES}") + target_compile_options("${_name}" PRIVATE ${GIGL_COMPILE_FLAGS}) + install(TARGETS "${_name}" DESTINATION "${_rel_dir}") +endforeach() diff --git a/Makefile b/Makefile index d20945f22..b8f4ebdfb 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ install_dev_deps: check_if_valid_env bash ./requirements/install_py_deps.sh --dev bash ./requirements/install_scala_deps.sh bash ./requirements/install_cpp_deps.sh - uv pip install -e . + uv pip install -e . --no-build-isolation uv run pre-commit install --hook-type pre-commit --hook-type pre-push # Production environments, if you are developing use `make install_dev_deps` instead @@ -59,7 +59,7 @@ install_deps: gcloud auth configure-docker us-central1-docker.pkg.dev bash ./requirements/install_py_deps.sh bash ./requirements/install_scala_deps.sh - uv pip install -e . + uv pip install -e . --no-build-isolation # These are a collection of tests that are run before anything is installed using tools available on host. # May include tests that check the sanity of the repo state i.e. ones that may even cause the failure of @@ -117,7 +117,7 @@ check_format_md: uv run mdformat --check ${MD_FILES} check_format_cpp: - $(if $(CPP_SOURCES), clang-format --dry-run --Werror --style=file $(CPP_SOURCES)) + $(if $(CPP_SOURCES), clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES)) check_format: check_format_py check_format_cpp check_format_scala check_format_md @@ -154,7 +154,7 @@ format_md: uv run mdformat ${MD_FILES} format_cpp: - $(if $(CPP_SOURCES), clang-format -i --style=file $(CPP_SOURCES)) + $(if $(CPP_SOURCES), clang-format-15 -i --style=file $(CPP_SOURCES)) format: format_py format_cpp format_scala format_md @@ -162,7 +162,7 @@ type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs build_cpp_extensions: - uv run --no-sync python -m scripts.build_cpp_extensions build_ext --inplace + uv pip install -e . --no-build-isolation generate_compile_commands: uv run python -m scripts.generate_compile_commands @@ -174,7 +174,7 @@ check_lint_cpp: # changes expressions, adds/removes keywords), not just style. Run manually and # review the diff before committing. fix_lint_cpp: generate_compile_commands - $(if $(CPP_SOURCES), clang-tidy --fix -p .cache/compile_commands.json $(CPP_SOURCES)) + $(if $(CPP_SOURCES), clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES)) lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index 66ecf8599..9c60ed0e5 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -9,6 +9,7 @@ WORKDIR /gigl # See https://beam.apache.org/documentation/sdks/python-pipxeline-dependencies/#create-reproducible-environments. WORKDIR /gigl +COPY CMakeLists.txt CMakeLists.txt COPY MANIFEST.in MANIFEST.in COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock @@ -21,4 +22,3 @@ COPY tests tests COPY examples examples RUN uv pip install -e . -RUN uv run python -m scripts.build_cpp_extensions build_ext --inplace diff --git a/gigl/csrc/cpp_compile_constants.py b/gigl/csrc/cpp_compile_constants.py deleted file mode 100644 index 2b64d151b..000000000 --- a/gigl/csrc/cpp_compile_constants.py +++ /dev/null @@ -1,9 +0,0 @@ -"""C++ compiler flags used by the pybind11 extension build and clangd compile commands generation.""" - -COMPILE_ARGS: list[str] = [ - "-O3", - "-std=c++17", - "-Wall", - "-Wextra", - "-Wno-unused-parameter", -] diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index 15f1bab99..3760ceb22 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -3,9 +3,9 @@ Once GiGL is installed w/ `pip install gigl`, this script can be executed by running: `gigl-post-install` -This script is used to install the dependencies for GIGL: -- Installs GLT by running install_glt.sh. -- Builds pybind11 C++ extensions in-place so they are importable without a separate build step. +This script installs GLT, which cannot be distributed as a standard wheel. +C++ extensions are built automatically by scikit-build-core during `pip install` +and do not require a separate step here. """ import subprocess @@ -18,9 +18,7 @@ def main(): print("Running GIGL post-install script...") script_dir = Path(__file__).parent - repo_root = script_dir.parent.parent - # Step 1: Install GLT install_glt_script = script_dir / "install_glt.sh" if not install_glt_script.exists(): print(f"Error: install_glt.sh not found at {install_glt_script}") @@ -34,33 +32,6 @@ def main(): print(f"Error installing GLT: {e}") sys.exit(1) - # Step 2: Build pybind11 C++ extensions in-place so they are importable - # without requiring a separate `make build_cpp_extensions` call. - # subprocess.run streams stdout/stderr to the terminal and raises - # CalledProcessError on a non-zero exit code. - build_cpp_script = repo_root / "scripts" / "build_cpp_extensions.py" - if not build_cpp_script.exists(): - print(f"Error: build_cpp_extensions.py not found at {build_cpp_script}") - sys.exit(1) - - try: - print("Building C++ extensions...") - subprocess.run( - [ - sys.executable, - "-m", - "scripts.build_cpp_extensions", - "build_ext", - "--inplace", - ], - cwd=repo_root, - check=True, - ) - print("C++ extension build finished.") - except subprocess.CalledProcessError as e: - print(f"Error building C++ extensions: {e}") - sys.exit(1) - if __name__ == "__main__": main() diff --git a/pyproject.toml b/pyproject.toml index d83e5587b..f3ba1e7c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,6 +107,8 @@ dev = [ {include-group = "test"}, {include-group = "typing-stubs"}, "pre-commit==3.3.2", + "scikit-build-core>=0.10", + "pybind11>=2.12", ] docs = [ "astroid==3.3.11", # Newer versions of astroid are not compatible with sphinx==7.4.7 @@ -227,14 +229,25 @@ torch_spline_conv = [ # ===================== Build/Project Configurations =========================== +# gigl releases two wheels (pyg27-torch28-cpu and pyg27-torch28-cu128), one +# built against CPU torch headers and one against CUDA torch headers. See +# release.yml for the build matrix. CMakeLists.txt auto-discovers python_*.cu +# files alongside python_*.cpp, so CUDA kernels can be added without changes +# to the build configuration. [build-system] -requires = ["setuptools>=61.0.0", "wheel"] -build-backend = "setuptools.build_meta" - +requires = [ + "scikit-build-core>=0.10", + "pybind11>=2.12", + "torch==2.8", # needed for torch headers at C++ compile time +] +build-backend = "scikit_build_core.build" -[tool.setuptools.packages.find] -where = ["."] # list of folders that contain the packages -include = ["gigl*", "snapchat*"] # Include only packages that match the specified patterns +[tool.scikit-build] +cmake.version = ">=3.18" +build-dir = ".cache/cmake_build" +wheel.packages = ["gigl", "snapchat"] +editable.mode = "redirect" # on import, checks if .cpp sources changed and rebuilds +editable.rebuild = true [project.urls] Homepage = "https://github.com/snapchat/gigl" diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 25570eab8..2c94927aa 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -7,14 +7,12 @@ # Called by `make install_dev_deps` alongside install_py_deps.sh and # install_scala_deps.sh. # -# NOTE: On Linux, this script calls apt-get and update-alternatives, which -# require root privileges. Run as root or prefix with sudo. +# NOTE: On Linux, this script calls apt-get, which requires root privileges. +# Run as root or prefix with sudo. set -e set -x -CLANG_VERSION=15 - is_running_on_mac() { [ "$(uname)" == "Darwin" ] return $? @@ -24,10 +22,10 @@ if is_running_on_mac; then # macOS ships its own Apple Clang via Xcode Command Line Tools. Homebrew # intentionally does not put its llvm binaries on PATH to avoid shadowing # Apple's clang. We therefore have to add the Homebrew llvm bin directory - # to PATH ourselves so that `clang-format` and `clang-tidy` resolve to the - # Homebrew versions rather than being missing entirely. - brew install llvm cmake - LLVM_BIN="$(brew --prefix llvm)/bin" + # to PATH ourselves so that `clang-format-15` and `clang-tidy-15` resolve + # to the correct versions rather than being missing entirely. + brew install llvm@15 cmake + LLVM_BIN="$(brew --prefix llvm@15)/bin" # Append to any shell rc files that exist and don't already include it. for rc_file in ~/.zshrc ~/.bashrc; do @@ -43,13 +41,10 @@ if is_running_on_mac; then export PATH="$LLVM_BIN:$PATH" else # On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly - # into /usr/bin. update-alternatives wires up the bare names (clang-format, - # clang-tidy) so callers don't need to specify the version suffix. No PATH - # changes are needed since /usr/bin is already on PATH. - apt-get install -y "clang-format-${CLANG_VERSION}" "clang-tidy-${CLANG_VERSION}" "clangd-${CLANG_VERSION}" cmake - update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-${CLANG_VERSION}" 100 - update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-${CLANG_VERSION}" 100 - update-alternatives --install /usr/bin/clangd clangd "/usr/bin/clangd-${CLANG_VERSION}" 100 + # into /usr/bin. No PATH changes are needed since /usr/bin is already on PATH. + # Callers use the versioned names (clang-format-15, clang-tidy-15, clangd-15) + # directly so the version is explicit and greppable across the codebase. + apt-get install -y clang-format-15 clang-tidy-15 clangd-15 cmake fi echo "Finished installing C++ tooling" diff --git a/scripts/build_cpp_extensions.py b/scripts/build_cpp_extensions.py deleted file mode 100644 index 85b5b13f2..000000000 --- a/scripts/build_cpp_extensions.py +++ /dev/null @@ -1,55 +0,0 @@ -"""Build script for GiGL pybind11 C++ extensions. - -Invoked by ``make build_cpp_extensions`` and automatically during ``make install_dev_deps`` -via ``post_install.py``. Not a general-purpose setup.py — only builds C++ extensions. - -Usage:: - - python build_cpp_extensions.py build_ext --inplace -""" - -from pathlib import Path - -from setuptools import setup -from setuptools.extension import Extension -from torch.utils.cpp_extension import BuildExtension, CppExtension - -from gigl.csrc.cpp_compile_constants import COMPILE_ARGS - -_REPO_ROOT: Path = Path(__file__).resolve().parent.parent -_CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" - - -def find_cpp_extensions() -> list[Extension]: - """Auto-discover pybind11 extension modules under ``gigl/csrc/``. - - Following PyTorch's csrc convention, only files named ``python_*.cpp`` are - compiled as Python extension modules. - - Returns an empty list if ``gigl/csrc/`` does not yet exist. - """ - if not _CSRC_DIR.exists(): - return [] - extensions = [] - for cpp_file in sorted(_CSRC_DIR.rglob("python_*.cpp")): - parts = list(cpp_file.with_suffix("").parts) - parts[-1] = parts[-1].removeprefix("python_") - module_name = ".".join(parts) - impl_file = cpp_file.parent / (parts[-1] + ".cpp") - sources = [str(cpp_file)] - if impl_file.exists(): - sources.append(str(impl_file)) - extensions.append( - CppExtension( - name=module_name, - sources=sources, - extra_compile_args=COMPILE_ARGS, - ) - ) - return extensions - - -setup( - ext_modules=find_cpp_extensions(), - cmdclass={"build_ext": BuildExtension}, -) diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index e71d76933..75f6d65b0 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -1,8 +1,7 @@ """Generate .cache/compile_commands.json for clangd. -clangd requires a compilation database to resolve include paths and compiler -flags. This script derives those paths from the installed torch and pybind11 -packages and writes ``.cache/compile_commands.json``. +Delegates to CMake (which already knows all include paths and compiler flags via +find_package(Torch)) rather than manually constructing the database. Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and by ``make generate_compile_commands`` when you need to refresh the database @@ -13,82 +12,30 @@ make generate_compile_commands """ -import json +import shutil import subprocess -import sys -import sysconfig -import warnings from pathlib import Path -from gigl.csrc.cpp_compile_constants import COMPILE_ARGS - _REPO_ROOT: Path = Path(__file__).resolve().parent.parent -_CSRC_DIR: Path = _REPO_ROOT / "gigl" / "csrc" +_CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build" _COMPILE_COMMANDS: Path = _REPO_ROOT / ".cache" / "compile_commands.json" -def _get_cxx_system_include_flags() -> list[str]: - """Return -isystem flags for the C++ standard library headers. - - clang++-15 on some machines is not configured with the correct GCC toolchain - path, so it cannot find standard headers like on its own. We ask - the system g++ compiler for its include search paths and pass them explicitly, - which is the reliable cross-machine approach. - """ - try: - result = subprocess.run( - ["c++", "-v", "-x", "c++", "-E", "/dev/null"], - capture_output=True, - text=True, - ) - includes: list[str] = [] - in_section = False - for line in result.stderr.splitlines(): - if "#include <...> search starts here:" in line: - in_section = True - continue - if "End of search list." in line: - break - if in_section and line.strip(): - includes.append(f"-isystem{line.strip()}") - return includes - except FileNotFoundError: - print( - "Warning: 'c++' not found; C++ system headers will be missing", - file=sys.stderr, - ) - return [] - - def write_compile_commands() -> None: - """Write .cache/compile_commands.json for clangd.""" - # Suppress PyTorch's CUDA-not-found warning emitted at import time. - with warnings.catch_warnings(): - warnings.filterwarnings("ignore") - from torch.utils.cpp_extension import include_paths as torch_include_paths - - # -isystem marks these as system headers so clangd skips deep analysis of - # PyTorch internals. - include_flags: list[str] = [f"-isystem{p}" for p in torch_include_paths()] - include_flags.append(f"-isystem{sysconfig.get_path('include')}") - include_flags.extend(_get_cxx_system_include_flags()) - - cpp_sources = sorted(_CSRC_DIR.rglob("*.cpp")) if _CSRC_DIR.exists() else [] - if not cpp_sources: - print(f"Warning: no .cpp files found under {_CSRC_DIR}", file=sys.stderr) - - cxx_flags = " ".join(COMPILE_ARGS) - commands: list[dict[str, str]] = [ - { - "directory": str(_REPO_ROOT), - "file": str(source), - "command": f"clang++ {cxx_flags} {' '.join(include_flags)} -c {source}", - } - for source in cpp_sources - ] - - _COMPILE_COMMANDS.parent.mkdir(exist_ok=True) - _COMPILE_COMMANDS.write_text(json.dumps(commands, indent=2)) + """Run CMake to generate .cache/compile_commands.json.""" + _CMAKE_BUILD_DIR.mkdir(parents=True, exist_ok=True) + subprocess.run( + [ + "cmake", + "-S", + str(_REPO_ROOT), + "-B", + str(_CMAKE_BUILD_DIR), + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + ], + check=True, + ) + shutil.copy(_CMAKE_BUILD_DIR / "compile_commands.json", _COMPILE_COMMANDS) def main() -> None: diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 69c834fa0..9c2cada46 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -24,7 +24,7 @@ def _check_file(source: Path) -> tuple[Path, list[str]]: result = subprocess.run( [ - "clangd", + "clangd-15", f"--check={source}", f"--compile-commands-dir={_COMPILE_COMMANDS.parent}", ], From 099dd2af4e0ea97ee0f4023eb27f18af1679b918 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 17 Apr 2026 22:52:02 +0000 Subject: [PATCH 047/148] Restore --- gigl/scripts/post_install.py | 45 ++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/gigl/scripts/post_install.py b/gigl/scripts/post_install.py index 3760ceb22..cd13c4b0b 100644 --- a/gigl/scripts/post_install.py +++ b/gigl/scripts/post_install.py @@ -3,33 +3,64 @@ Once GiGL is installed w/ `pip install gigl`, this script can be executed by running: `gigl-post-install` -This script installs GLT, which cannot be distributed as a standard wheel. -C++ extensions are built automatically by scikit-build-core during `pip install` -and do not require a separate step here. +This script is used to install the dependencies for GIGL. +- Currently, it installs GLT by running install_glt.sh. """ import subprocess import sys from pathlib import Path +from typing import Optional + + +def run_command_and_stream_stdout(cmd: str) -> Optional[int]: + """ + Executes a command and streams the stdout output. + + Args: + cmd (str): The command to be executed. + + Returns: + Optional[int]: The return code of the command, or None if the command failed to execute. + """ + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + while True: + output = process.stdout.readline() # type: ignore + if output == b"" and process.poll() is not None: + break + if output: + print(output.strip()) + return_code: Optional[int] = process.poll() + return return_code def main(): """Main entry point for the post-install script.""" print("Running GIGL post-install script...") + # Get the directory where this script is located script_dir = Path(__file__).parent + # Path to the install_glt.sh script install_glt_script = script_dir / "install_glt.sh" + if not install_glt_script.exists(): print(f"Error: install_glt.sh not found at {install_glt_script}") sys.exit(1) + cmd = f"bash {install_glt_script}" + try: - print(f"Installing GLT via {install_glt_script}...") - subprocess.run(["bash", str(install_glt_script)], check=True) - print("GLT install finished.") + print(f"Executing {cmd}...") + result = run_command_and_stream_stdout(cmd) + print("Post-install script finished running, with return code: ", result) + return result + except subprocess.CalledProcessError as e: - print(f"Error installing GLT: {e}") + print(f"Error running install_glt.sh: {e}") + sys.exit(1) + except Exception as e: + print(f"Unexpected error: {e}") sys.exit(1) From 830da8bf2e2edbc2db71f5c805159e2cc9a0f0dc Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 17 Apr 2026 23:18:51 +0000 Subject: [PATCH 048/148] Update --- CMakeLists.txt | 9 +++++++++ requirements/install_cpp_deps.sh | 6 +++++- scripts/generate_compile_commands.py | 20 ++++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 51c492aba..452585658 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,15 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) + +# Locate pybind11's cmake config via the Python interpreter so this works +# whether pybind11 is installed system-wide or via pip. +execute_process( + COMMAND "${Python_EXECUTABLE}" -c + "import pybind11; print(pybind11.get_cmake_dir())" + OUTPUT_VARIABLE pybind11_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) find_package(pybind11 CONFIG REQUIRED) # Locate PyTorch headers via its own cmake prefix path (works for both CPU and CUDA torch). diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 2c94927aa..6bfb233a2 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -44,7 +44,11 @@ else # into /usr/bin. No PATH changes are needed since /usr/bin is already on PATH. # Callers use the versioned names (clang-format-15, clang-tidy-15, clangd-15) # directly so the version is explicit and greppable across the codebase. - apt-get install -y clang-format-15 clang-tidy-15 clangd-15 cmake + # clang++-15 requires libstdc++-12-dev: on Ubuntu 22.04, clang++-15 looks for GCC 12 + # headers. Without this package clang++-15 cannot find standard headers like . + # clang++-15 itself is needed because generate_compile_commands.py rewrites + # compile_commands.json to use it so clangd natively understands the commands. + apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake fi echo "Finished installing C++ tooling" diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 75f6d65b0..15e446de8 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -3,6 +3,11 @@ Delegates to CMake (which already knows all include paths and compiler flags via find_package(Torch)) rather than manually constructing the database. +The build uses the system C++ compiler (g++) so that cmake, nvcc, and Torch's +cmake work without issues. After cmake writes compile_commands.json, the +compiler in each entry is replaced with ``clang++-15`` so that clangd natively +understands the commands without needing a ``--query-driver`` workaround. + Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and by ``make generate_compile_commands`` when you need to refresh the database manually (e.g. after adding new source files or changing compiler flags). @@ -12,7 +17,7 @@ make generate_compile_commands """ -import shutil +import json import subprocess from pathlib import Path @@ -35,7 +40,18 @@ def write_compile_commands() -> None: ], check=True, ) - shutil.copy(_CMAKE_BUILD_DIR / "compile_commands.json", _COMPILE_COMMANDS) + + raw_path = _CMAKE_BUILD_DIR / "compile_commands.json" + entries: list[dict] = json.loads(raw_path.read_text()) + + # Replace the first token of each command (the compiler binary) with clang++-15 + # so clangd uses clang-native implicit include paths instead of guessing GCC's. + for entry in entries: + tokens = entry["command"].split() + tokens[0] = "clang++-15" + entry["command"] = " ".join(tokens) + + _COMPILE_COMMANDS.write_text(json.dumps(entries, indent=2)) def main() -> None: From 3afb8a261e8ed5c1f27f118652eb77fe921845bc Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sat, 18 Apr 2026 01:38:46 +0000 Subject: [PATCH 049/148] Update --- CMakeLists.txt | 16 +++++++++++++++- scripts/generate_compile_commands.py | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 452585658..c3d8d7fd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,17 @@ endif() find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") +# torch_python provides the pybind11 type casters for at::Tensor. It is not +# included in TORCH_LIBRARIES but is required for extensions that pass tensors +# across the Python/C++ boundary. +execute_process( + COMMAND "${Python_EXECUTABLE}" -c + "import torch, os; print(os.path.join(os.path.dirname(torch.__file__), 'lib'))" + OUTPUT_VARIABLE TORCH_LIB_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_LIB_DIR}" REQUIRED) + set(GIGL_COMPILE_FLAGS -O3 -Wall -Wextra -Wno-unused-parameter) # --------------------------------------------------------------------------- @@ -63,7 +74,10 @@ foreach(_py_src IN LISTS _PYTHON_SRCS) file(RELATIVE_PATH _rel_dir "${CMAKE_SOURCE_DIR}" "${_dir}") pybind11_add_module("${_name}" ${_sources}) - target_link_libraries("${_name}" PRIVATE "${TORCH_LIBRARIES}") + target_link_libraries("${_name}" PRIVATE "${TORCH_LIBRARIES}" "${TORCH_PYTHON_LIBRARY}") target_compile_options("${_name}" PRIVATE ${GIGL_COMPILE_FLAGS}) + # TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. + # PyTorch's own build system sets this; we must define it explicitly here. + target_compile_definitions("${_name}" PRIVATE "TORCH_EXTENSION_NAME=${_name}") install(TARGETS "${_name}" DESTINATION "${_rel_dir}") endforeach() diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 15e446de8..d2dd6b087 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -22,7 +22,7 @@ from pathlib import Path _REPO_ROOT: Path = Path(__file__).resolve().parent.parent -_CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build" +_CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build_lint" _COMPILE_COMMANDS: Path = _REPO_ROOT / ".cache" / "compile_commands.json" From b37786cfbe216f338373f2a11b9ed9cf967ccabc Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 17:48:29 +0000 Subject: [PATCH 050/148] Update --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f3ba1e7c1..660b293f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -246,8 +246,7 @@ build-backend = "scikit_build_core.build" cmake.version = ">=3.18" build-dir = ".cache/cmake_build" wheel.packages = ["gigl", "snapchat"] -editable.mode = "redirect" # on import, checks if .cpp sources changed and rebuilds -editable.rebuild = true +editable.mode = "redirect" [project.urls] Homepage = "https://github.com/snapchat/gigl" From ab51157b470e1ae0fc396c01da19b6762de8e7ed Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 18:19:33 +0000 Subject: [PATCH 051/148] Update --- CMakeLists.txt | 14 +++++++++----- Makefile | 8 ++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3d8d7fd9..66fdaf32d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,11 +25,10 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) -# CUDA torch's CMake unconditionally calls enable_language(CUDA), which requires nvcc. -# nvcc may not be on PATH even when the CUDA toolkit is installed; find it explicitly. -if(NOT CMAKE_CUDA_COMPILER) - find_program(CMAKE_CUDA_COMPILER nvcc PATHS "/usr/local/cuda/bin") -endif() +# Our extensions have no CUDA kernels. When a CUDA-enabled torch is installed +# but the CUDA toolkit is absent (e.g. CPU-only CI), Caffe2Config.cmake aborts +# unless we disable the CUDA check before calling find_package(Torch). +set(CAFFE2_USE_CUDA OFF CACHE BOOL "" FORCE) find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") @@ -44,6 +43,11 @@ execute_process( ) find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_LIB_DIR}" REQUIRED) +# Preserve torch lib dir in the installed .so RPATH so the extension loads +# libtorch.so without requiring `import torch` to pre-populate the symbol table. +set(CMAKE_INSTALL_RPATH "${TORCH_LIB_DIR}") +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + set(GIGL_COMPILE_FLAGS -O3 -Wall -Wextra -Wno-unused-parameter) # --------------------------------------------------------------------------- diff --git a/Makefile b/Makefile index b8f4ebdfb..06c488e7d 100644 --- a/Makefile +++ b/Makefile @@ -117,7 +117,7 @@ check_format_md: uv run mdformat --check ${MD_FILES} check_format_cpp: - $(if $(CPP_SOURCES), clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES)) + clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES) check_format: check_format_py check_format_cpp check_format_scala check_format_md @@ -154,7 +154,7 @@ format_md: uv run mdformat ${MD_FILES} format_cpp: - $(if $(CPP_SOURCES), clang-format-15 -i --style=file $(CPP_SOURCES)) + clang-format-15 -i --style=file $(CPP_SOURCES) format: format_py format_cpp format_scala format_md @@ -168,13 +168,13 @@ generate_compile_commands: uv run python -m scripts.generate_compile_commands check_lint_cpp: - $(if $(CPP_SOURCES), uv run python -m scripts.run_cpp_lint $(CPP_SOURCES)) + uv run python -m scripts.run_cpp_lint $(CPP_SOURCES) # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, # changes expressions, adds/removes keywords), not just style. Run manually and # review the diff before committing. fix_lint_cpp: generate_compile_commands - $(if $(CPP_SOURCES), clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES)) + clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES) lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" From df98b208985806ba2de100399bcb269aef013026 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 18:31:22 +0000 Subject: [PATCH 052/148] Fix --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- CMakeLists.txt | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index d0e407f02..153a704db 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -29,7 +29,7 @@ steps: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes gcloud auth configure-docker us-central1-docker.pkg.dev # Install GiGL - uv pip install -e . + uv pip install -e . --no-build-isolation # The builder operates in its own user dir, usually /workspace, # so we need to copy the gigl tools dir to the current cloud_builder's user dir. # See: containers/Dockerfile.builder. diff --git a/CMakeLists.txt b/CMakeLists.txt index 66fdaf32d..5249720a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,11 +25,6 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) -# Our extensions have no CUDA kernels. When a CUDA-enabled torch is installed -# but the CUDA toolkit is absent (e.g. CPU-only CI), Caffe2Config.cmake aborts -# unless we disable the CUDA check before calling find_package(Torch). -set(CAFFE2_USE_CUDA OFF CACHE BOOL "" FORCE) - find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") # torch_python provides the pybind11 type casters for at::Tensor. It is not From 1165fd37c5bca3d0f94b73142defc2abc75873c9 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 18:52:42 +0000 Subject: [PATCH 053/148] Fixes --- .github/workflows/release-documentation.yml | 2 +- containers/Dockerfile.dataflow.src | 4 +++- containers/Dockerfile.src | 4 ++-- mypy.ini | 2 -- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-documentation.yml b/.github/workflows/release-documentation.yml index 044492888..d6efc650d 100644 --- a/.github/workflows/release-documentation.yml +++ b/.github/workflows/release-documentation.yml @@ -45,7 +45,7 @@ jobs: - name: Install necessary doc dependencies run: | uv sync --group docs --inexact - uv pip install -e . + uv pip install -e . --no-build-isolation - name: Sphinx build run: | make build_docs diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index b5d29c7f0..973604f13 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -5,6 +5,7 @@ FROM $BASE_IMAGE # Copy the source WORKDIR /gigl +COPY CMakeLists.txt CMakeLists.txt COPY MANIFEST.in MANIFEST.in COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock @@ -13,6 +14,7 @@ COPY deployment deployment COPY gigl gigl COPY snapchat snapchat COPY tests tests -RUN uv pip install -e . +RUN uv pip install scikit-build-core pybind11 +RUN uv pip install -e . --no-build-isolation WORKDIR / diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index 9c60ed0e5..1dd641cb2 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -16,9 +16,9 @@ COPY uv.lock uv.lock COPY gigl/dep_vars.env gigl/dep_vars.env COPY deployment deployment COPY gigl gigl -COPY scripts scripts COPY snapchat snapchat COPY tests tests COPY examples examples -RUN uv pip install -e . +RUN uv pip install scikit-build-core pybind11 +RUN uv pip install -e . --no-build-isolation diff --git a/mypy.ini b/mypy.ini index b034f60d4..b8b588631 100644 --- a/mypy.ini +++ b/mypy.ini @@ -16,8 +16,6 @@ ignore_missing_imports = True [mypy-setuptools] ignore_missing_imports = True -[mypy-setuptools.extension] -ignore_missing_imports = True [mypy-tensorflow_data_validation] ignore_missing_imports = True From 4b579aa69bc482582a8a882a1e87d84fbc2f5ca4 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 19:03:58 +0000 Subject: [PATCH 054/148] Update --- gigl/orchestration/Dockerfile.customer_src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gigl/orchestration/Dockerfile.customer_src b/gigl/orchestration/Dockerfile.customer_src index 25a5ea762..afa3d124c 100644 --- a/gigl/orchestration/Dockerfile.customer_src +++ b/gigl/orchestration/Dockerfile.customer_src @@ -10,4 +10,4 @@ WORKDIR /gigl COPY . . # Find out if there is 'setup.py' or 'pyproject.toml' in the current directory, if so install it -RUN if [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then pip install -e .; fi +RUN if [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then uv pip install scikit-build-core pybind11 && uv pip install -e . --no-build-isolation; fi From f4b015e143546f840b2bba8939f03ac21b39b78f Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 20:11:19 +0000 Subject: [PATCH 055/148] Update uv lock --- uv.lock | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/uv.lock b/uv.lock index 393a9a275..4d6eb9227 100644 --- a/uv.lock +++ b/uv.lock @@ -640,8 +640,8 @@ dependencies = [ { name = "numpy", marker = "sys_platform != 'darwin'" }, ] wheels = [ - { url = "https://download.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4154e803ba762906a604a72aa41685fdd49459fce55cea79d42ac7c45c8770ca" }, - { url = "https://download.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0267ec844b43028f4b9b8e14acd16276e82bb97f91b6b1078f732eb9225b20c6" }, + { url = "https://download-r2.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4154e803ba762906a604a72aa41685fdd49459fce55cea79d42ac7c45c8770ca" }, + { url = "https://download-r2.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0267ec844b43028f4b9b8e14acd16276e82bb97f91b6b1078f732eb9225b20c6" }, ] [[package]] @@ -652,7 +652,7 @@ dependencies = [ { name = "numpy" }, ] wheels = [ - { url = "https://download.pytorch.org/whl/cu128/fbgemm_gpu-1.3.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:365a2c7f89e89f6d8acf3af5101cbb1651cd1cc64057fd2902feae490814cee3" }, + { url = "https://download-r2.pytorch.org/whl/cu128/fbgemm_gpu-1.3.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:365a2c7f89e89f6d8acf3af5101cbb1651cd1cc64057fd2902feae490814cee3" }, ] [[package]] @@ -819,7 +819,9 @@ dev = [ { name = "pandas-stubs" }, { name = "parameterized" }, { name = "pre-commit" }, + { name = "pybind11" }, { name = "pydata-sphinx-theme" }, + { name = "scikit-build-core" }, { name = "sphinx" }, { name = "sphinx-autoapi" }, { name = "sphinx-autodoc-typehints" }, @@ -944,7 +946,9 @@ dev = [ { name = "pandas-stubs", specifier = "==2.2.2.240807" }, { name = "parameterized", specifier = "==0.9.0" }, { name = "pre-commit", specifier = "==3.3.2" }, + { name = "pybind11", specifier = ">=2.12" }, { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, + { name = "scikit-build-core", specifier = ">=0.10" }, { name = "sphinx", specifier = "==7.4.7" }, { name = "sphinx-autoapi", specifier = "==3.6.0" }, { name = "sphinx-autodoc-typehints", specifier = "==2.3.0" }, @@ -3107,6 +3111,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] +[[package]] +name = "pybind11" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/f0/35145a3c3baffeef55d4b8324caa33abaa8fa56ab345ecd4b2211d09163e/pybind11-3.0.4.tar.gz", hash = "sha256:3286b59c8a774b9ee650169302dd5a4eedc30a8617905a0560dd8ee44775130c", size = 589533, upload-time = "2026-04-19T03:08:15.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/06/c3a23c9a0263b136c519f033a58d4641e73065fefc7754e9667ec206d992/pybind11-3.0.4-py3-none-any.whl", hash = "sha256:961720ee652da51d531b7b2451a6bd2bc042b0106e6d9baa48ecb7d58034ce63", size = 314166, upload-time = "2026-04-19T03:08:14.091Z" }, +] + [[package]] name = "pycparser" version = "2.23" @@ -3554,6 +3567,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, ] +[[package]] +name = "scikit-build-core" +version = "0.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pathspec" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/cd/9ebb50029b6d8a3ee9e38cdce514ebd70190ec1edf28ab0a1f66d0b84670/scikit_build_core-0.12.2.tar.gz", hash = "sha256:562e0bbc9de1a354c87825ccf732080268d6582a0200f648e8c4a2dcb1e3736d", size = 303553, upload-time = "2026-03-05T18:25:57.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/49/b2f0fbe3165d55c02e7f9eec6a10685d518af0ef6e919ff2f589c2d15c85/scikit_build_core-0.12.2-py3-none-any.whl", hash = "sha256:6ea4730da400f9a998ec3287bd3ebc1d751fe45ad0a93451bead8618adbc02b1", size = 192625, upload-time = "2026-03-05T18:25:56.207Z" }, +] + [[package]] name = "scikit-learn" version = "1.7.2" @@ -4162,7 +4188,7 @@ dependencies = [ { name = "typing-extensions", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, ] wheels = [ - { url = "https://download.pytorch.org/whl/cpu/torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:3d05017d19bc99741288e458888283a44b0ee881d53f05f72f8b1cfea8998122" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:3d05017d19bc99741288e458888283a44b0ee881d53f05f72f8b1cfea8998122" }, ] [[package]] @@ -4182,11 +4208,11 @@ dependencies = [ { name = "typing-extensions", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] wheels = [ - { url = "https://download.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-linux_s390x.whl", hash = "sha256:2bfc013dd6efdc8f8223a0241d3529af9f315dffefb53ffa3bf14d3f10127da6" }, - { url = "https://download.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:680129efdeeec3db5da3f88ee5d28c1b1e103b774aef40f9d638e2cce8f8d8d8" }, - { url = "https://download.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cb06175284673a581dd91fb1965662ae4ecaba6e5c357aa0ea7bb8b84b6b7eeb" }, - { url = "https://download.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_amd64.whl", hash = "sha256:7631ef49fbd38d382909525b83696dc12a55d68492ade4ace3883c62b9fc140f" }, - { url = "https://download.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_arm64.whl", hash = "sha256:41e6fc5ec0914fcdce44ccf338b1d19a441b55cafdd741fd0bf1af3f9e4cfd14" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-linux_s390x.whl", hash = "sha256:2bfc013dd6efdc8f8223a0241d3529af9f315dffefb53ffa3bf14d3f10127da6" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:680129efdeeec3db5da3f88ee5d28c1b1e103b774aef40f9d638e2cce8f8d8d8" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cb06175284673a581dd91fb1965662ae4ecaba6e5c357aa0ea7bb8b84b6b7eeb" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_amd64.whl", hash = "sha256:7631ef49fbd38d382909525b83696dc12a55d68492ade4ace3883c62b9fc140f" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_arm64.whl", hash = "sha256:41e6fc5ec0914fcdce44ccf338b1d19a441b55cafdd741fd0bf1af3f9e4cfd14" }, ] [[package]] @@ -4217,8 +4243,8 @@ dependencies = [ { name = "typing-extensions", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, ] wheels = [ - { url = "https://download.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:039b9dcdd6bdbaa10a8a5cd6be22c4cb3e3589a341e5f904cbb571ca28f55bed" }, - { url = "https://download.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-win_amd64.whl", hash = "sha256:34c55443aafd31046a7963b63d30bc3b628ee4a704f826796c865fdfd05bb596" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:039b9dcdd6bdbaa10a8a5cd6be22c4cb3e3589a341e5f904cbb571ca28f55bed" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-win_amd64.whl", hash = "sha256:34c55443aafd31046a7963b63d30bc3b628ee4a704f826796c865fdfd05bb596" }, ] [[package]] From 0f253d2122f1ce8b76948f6dce996eaca9ef4ad5 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 20:28:12 +0000 Subject: [PATCH 056/148] Update --- pyproject.toml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ad0d76a6f..16a6ab30d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -236,7 +236,6 @@ torch_spline_conv = [ requires = [ "scikit-build-core>=0.10", "pybind11>=2.12", - "torch==2.8", # needed for torch headers at C++ compile time ] build-backend = "scikit_build_core.build" @@ -252,12 +251,6 @@ Homepage = "https://github.com/snapchat/gigl" [project.scripts] gigl-post-install = "gigl.scripts.post_install:main" -[tool.setuptools.package-data] -# Include dep_vars.env from the root directory -"gigl" = ["dep_vars.env", "**/*.yaml"] -"gigl.scripts" = ["*.sh"] - - [tool.ruff] # Skip generated proto files. exclude = ["*_pb2.py", "*_pb2.pyi"] From 18a731621ac30401438ea40487a73d0bc151cb19 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 20:41:11 +0000 Subject: [PATCH 057/148] Fix --- requirements/install_py_deps.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index 6a328165e..3c123c5fa 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -138,12 +138,17 @@ install_gigl_lib_deps() { flag_use_inexact_match="--inexact" fi + # --no-install-project: skip building and installing the gigl package itself here. + # The project is installed separately via `uv pip install -e . --no-build-isolation` + # (see Makefile install_dev_deps/install_deps targets and the *.src Dockerfiles). + # This avoids scikit-build-core requiring all source files (e.g. README.md, CMakeLists.txt) + # to be present in environments that only need the dependencies (e.g. base Docker images). if [[ $DEV -eq 1 ]] then # https://docs.astral.sh/uv/reference/cli/#uv-sync - uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} + uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} --no-install-project else - uv sync ${extra_deps_clause[@]} --locked ${flag_use_inexact_match} + uv sync ${extra_deps_clause[@]} --locked ${flag_use_inexact_match} --no-install-project fi # Taken from https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script @@ -151,7 +156,10 @@ install_gigl_lib_deps() { if [[ "${SKIP_GLT_POST_INSTALL}" -eq 0 ]] then SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - uv run python $SCRIPT_DIR/../gigl/scripts/post_install.py + # --no-project: prevents uv from trying to install the gigl project before running + # the script. We intentionally skipped installing it above (--no-install-project), + # and post_install.py only runs install_glt.sh — it does not need gigl installed. + uv run --no-project python $SCRIPT_DIR/../gigl/scripts/post_install.py fi } From b56945e04d296d70575f76a7fa5f892be92cf088 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 20:42:19 +0000 Subject: [PATCH 058/148] Bump pyproject version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 16a6ab30d..4c5cdcfab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "gigl" description = "GIgantic Graph Learning Library" readme = "README.md" -version = "0.2.0" +version = "0.3.0" classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", From 30e4e309ebff6ac167c09efa0ae70cc80b2c22c9 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 20:48:14 +0000 Subject: [PATCH 059/148] bump back to 0.2.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4c5cdcfab..16a6ab30d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "gigl" description = "GIgantic Graph Learning Library" readme = "README.md" -version = "0.3.0" +version = "0.2.0" classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", From cbf07f3d981389bcaceb251de889f94ce0216a76 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 20 Apr 2026 20:58:38 +0000 Subject: [PATCH 060/148] [AUTOMATED] Update dep.vars, and other relevant files with new image names --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- gigl/dep_vars.env | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index 153a704db..da7fd0f4e 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 entrypoint: /bin/bash args: - -c diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index 85ef4d21b..7841701e1 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 From 870e93636233dfbfe78c27faa18b168f007d95e2 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 21:10:39 +0000 Subject: [PATCH 061/148] Add cpp test to gh comment --- .github/workflows/on-pr-comment.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/on-pr-comment.yml b/.github/workflows/on-pr-comment.yml index 870c415fe..1a5020ffb 100644 --- a/.github/workflows/on-pr-comment.yml +++ b/.github/workflows/on-pr-comment.yml @@ -64,6 +64,26 @@ jobs: command: | make unit_test_py + unit-test-cpp: + if: ${{ github.event.issue.pull_request && (contains(github.event.comment.body, '/unit_test_cpp') || endsWith(github.event.comment.body, '/unit_test') || contains(github.event.comment.body, '/all_test')) }} + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Run C++ Unit Tests + uses: snapchat/gigl/.github/actions/run-command-on-pr@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + pr_number: ${{ github.event.issue.number }} + should_leave_progress_comments: "true" + descriptive_workflow_name: "C++ Unit Test" + setup_gcloud: "true" + use_cloud_run: "true" + gcp_project_id: ${{ vars.GCP_PROJECT_ID }} + workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + gcp_service_account_email: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + command: | + make unit_test_cpp + unit-test-scala: if: ${{ github.event.issue.pull_request && (contains(github.event.comment.body, '/unit_test_scala') || endsWith(github.event.comment.body, '/unit_test') || contains(github.event.comment.body, '/all_test')) }} runs-on: ubuntu-latest From 77e1a0282ddbf44866645dc8a84c2b577c278249 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 21:42:39 +0000 Subject: [PATCH 062/148] Update dockerfile with readme --- containers/Dockerfile.dataflow.src | 1 + containers/Dockerfile.src | 1 + 2 files changed, 2 insertions(+) diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index 973604f13..5e3c9f9e7 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -7,6 +7,7 @@ WORKDIR /gigl COPY CMakeLists.txt CMakeLists.txt COPY MANIFEST.in MANIFEST.in +COPY README.md README.md COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock COPY gigl/dep_vars.env gigl/dep_vars.env diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index 1dd641cb2..c897e7465 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -11,6 +11,7 @@ WORKDIR /gigl COPY CMakeLists.txt CMakeLists.txt COPY MANIFEST.in MANIFEST.in +COPY README.md README.md COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock COPY gigl/dep_vars.env gigl/dep_vars.env From ce9f1e2f7b0b017c74583938d59a0c184de66cf5 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 23:11:26 +0000 Subject: [PATCH 063/148] update style guide --- docs/cpp_style_guide.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 33d3a2144..612917fe6 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -151,3 +151,26 @@ Enforced via `readability-identifier-naming`: | `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | | `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | | `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | + +______________________________________________________________________ + +## pybind11 Extension Modules + +Extension modules live under `gigl/csrc/`. + +### Naming convention + +| File | Purpose | +| -------------------------- | ---------------------------------------------------------------------------------------------------- | +| `python_.cpp` | pybind11 bindings — contains the `PYBIND11_MODULE` definition | +| `.cpp` / `.cu` | Implementation — function and class definitions | +| `.h` | Declarations (function signatures, class definitions, constants) shared across multiple `.cpp` files | + +Example: to add a `my_op` extension under `gigl/csrc/sampling/`: + +``` +gigl/csrc/sampling/python_my_op.cpp ← pybind11 bindings +gigl/csrc/sampling/my_op.cpp ← implementation +``` + +The compiled `.so` is installed to the same directory and importable as `gigl.csrc.sampling.my_op`. From 61f4965ff1eec5fa4ea0e44318b71bb303cc8dc7 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 23:12:50 +0000 Subject: [PATCH 064/148] Small update --- docs/cpp_style_guide.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 612917fe6..97eb9447c 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -160,11 +160,11 @@ Extension modules live under `gigl/csrc/`. ### Naming convention -| File | Purpose | -| -------------------------- | ---------------------------------------------------------------------------------------------------- | -| `python_.cpp` | pybind11 bindings — contains the `PYBIND11_MODULE` definition | -| `.cpp` / `.cu` | Implementation — function and class definitions | -| `.h` | Declarations (function signatures, class definitions, constants) shared across multiple `.cpp` files | +| File | Purpose | +| -------------------------- | ---------------------------------------------------------------- | +| `python_.cpp` | pybind11 bindings — contains the `PYBIND11_MODULE` definition | +| `.cpp` / `.cu` | Implementation — function and class definitions | +| `.h` | Declarations (function signatures, class definitions, constants) | Example: to add a `my_op` extension under `gigl/csrc/sampling/`: From 3af2a330189d0764e263b32c1968050c204c84a6 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 23:15:19 +0000 Subject: [PATCH 065/148] remove mypy change --- mypy.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/mypy.ini b/mypy.ini index b8b588631..d488c2a83 100644 --- a/mypy.ini +++ b/mypy.ini @@ -16,7 +16,6 @@ ignore_missing_imports = True [mypy-setuptools] ignore_missing_imports = True - [mypy-tensorflow_data_validation] ignore_missing_imports = True From f4173652abbf956c1e4ef1935756cd6ce0a09b87 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 20 Apr 2026 23:53:03 +0000 Subject: [PATCH 066/148] Make necessary changes for when we need to introduce cuda cpp operations --- CMakeLists.txt | 35 +++++++++++++++++++++------- MANIFEST.in | 1 + Makefile | 9 ++++--- scripts/generate_compile_commands.py | 12 ++++++---- tests/unit/cpp/CMakeLists.txt | 14 ++++++++++- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5249720a5..e2e441842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,16 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# Enable CUDA only when the toolkit is present; allows the same CMakeLists.txt +# to build on CPU-only machines without requiring nvcc. +include(CheckLanguage) +check_language(CUDA) +if(CMAKE_CUDA_COMPILER) + enable_language(CUDA) + set(CMAKE_CUDA_STANDARD 17) + set(CMAKE_CUDA_STANDARD_REQUIRED ON) +endif() + find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) # Locate pybind11's cmake config via the Python interpreter so this works @@ -53,10 +63,16 @@ set(GIGL_COMPILE_FLAGS -O3 -Wall -Wextra -Wno-unused-parameter) # build_cpp_extensions.py: no changes here are needed to add new extensions. # --------------------------------------------------------------------------- -file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cpp" - "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cu" -) +if(CMAKE_CUDA_COMPILER) + file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS + "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cpp" + "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cu" + ) +else() + file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS + "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cpp" + ) +endif() foreach(_py_src IN LISTS _PYTHON_SRCS) get_filename_component(_dir "${_py_src}" DIRECTORY) @@ -64,11 +80,12 @@ foreach(_py_src IN LISTS _PYTHON_SRCS) string(REGEX REPLACE "^python_" "" _name "${_stem}") set(_sources "${_py_src}") - foreach(_ext IN ITEMS cpp cu) - if(EXISTS "${_dir}/${_name}.${_ext}") - list(APPEND _sources "${_dir}/${_name}.${_ext}") - endif() - endforeach() + if(EXISTS "${_dir}/${_name}.cpp") + list(APPEND _sources "${_dir}/${_name}.cpp") + endif() + if(CMAKE_CUDA_COMPILER AND EXISTS "${_dir}/${_name}.cu") + list(APPEND _sources "${_dir}/${_name}.cu") + endif() file(RELATIVE_PATH _rel_dir "${CMAKE_SOURCE_DIR}" "${_dir}") diff --git a/MANIFEST.in b/MANIFEST.in index ec343c7d5..f7ce04948 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ global-exclude tests/* recursive-include gigl/deps *.jar +recursive-include gigl/csrc *.cpp *.cu *.h diff --git a/Makefile b/Makefile index e3723177d..7867aacfb 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,10 @@ DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG?=${DOCKER_IMAGE_MAIN_CPU_NAME}:${DATE} DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${DATE} PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts -CPP_SOURCES:=$(shell find gigl/csrc -name "*.cpp" 2>/dev/null) +CPP_SOURCES:=$(shell find gigl/csrc -name "*.cpp" -o -name "*.cu" 2>/dev/null) +# clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). +# Exclude .cu files from tidy targets; clang-format and clangd handle them fine. +CPP_SOURCES_NO_CUDA:=$(filter-out %.cu,$(CPP_SOURCES)) PY_TEST_FILES?="*_test.py" # You can override GIGL_TEST_DEFAULT_RESOURCE_CONFIG by setting it in your environment i.e. # adding `export GIGL_TEST_DEFAULT_RESOURCE_CONFIG=your_resource_config` to your shell config (~/.bashrc, ~/.zshrc, etc.) @@ -166,13 +169,13 @@ generate_compile_commands: uv run python -m scripts.generate_compile_commands check_lint_cpp: - uv run python -m scripts.run_cpp_lint $(CPP_SOURCES) + uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA) # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, # changes expressions, adds/removes keywords), not just style. Run manually and # review the diff before committing. fix_lint_cpp: generate_compile_commands - clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES) + clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES_NO_CUDA) lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index d2dd6b087..f0a39b2cc 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -44,12 +44,14 @@ def write_compile_commands() -> None: raw_path = _CMAKE_BUILD_DIR / "compile_commands.json" entries: list[dict] = json.loads(raw_path.read_text()) - # Replace the first token of each command (the compiler binary) with clang++-15 - # so clangd uses clang-native implicit include paths instead of guessing GCC's. + # Replace the compiler for .cpp entries with clang++-15 so clangd uses + # clang-native implicit include paths instead of guessing GCC's. + # Leave .cu entries unchanged so nvcc handles them correctly. for entry in entries: - tokens = entry["command"].split() - tokens[0] = "clang++-15" - entry["command"] = " ".join(tokens) + if not entry.get("file", "").endswith(".cu"): + tokens = entry["command"].split() + tokens[0] = "clang++-15" + entry["command"] = " ".join(tokens) _COMPILE_COMMANDS.write_text(json.dumps(entries, indent=2)) diff --git a/tests/unit/cpp/CMakeLists.txt b/tests/unit/cpp/CMakeLists.txt index 8b0ed16e7..4fd05b316 100644 --- a/tests/unit/cpp/CMakeLists.txt +++ b/tests/unit/cpp/CMakeLists.txt @@ -5,6 +5,14 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +include(CheckLanguage) +check_language(CUDA) +if(CMAKE_CUDA_COMPILER) + enable_language(CUDA) + set(CMAKE_CUDA_STANDARD 17) + set(CMAKE_CUDA_STANDARD_REQUIRED ON) +endif() + # --------------------------------------------------------------------------- # GoogleTest via FetchContent # --------------------------------------------------------------------------- @@ -29,7 +37,11 @@ enable_testing() # automatically compiled into its own test binary and registered with CTest. # To add a new test suite, drop a *_test.cpp file here — no changes to this # file required. This matches the *_test.py convention used for Python tests. -file(GLOB_RECURSE TEST_SOURCES "*_test.cpp") +if(CMAKE_CUDA_COMPILER) + file(GLOB_RECURSE TEST_SOURCES "*_test.cpp" "*_test.cu") +else() + file(GLOB_RECURSE TEST_SOURCES "*_test.cpp") +endif() foreach(test_source ${TEST_SOURCES}) # Derive the binary name from the filename, e.g.: From 83bb8a64f85097669b50a6b69deb7108b59eb225 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 21 Apr 2026 00:00:25 +0000 Subject: [PATCH 067/148] Additional fixes to cuda setup --- CMakeLists.txt | 7 ++++++- MANIFEST.in | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2e441842..274193709 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,8 @@ set(CMAKE_INSTALL_RPATH "${TORCH_LIB_DIR}") set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(GIGL_COMPILE_FLAGS -O3 -Wall -Wextra -Wno-unused-parameter) +# nvcc does not accept bare -Wall/-Wextra; wrap them with -Xcompiler for CUDA sources. +set(GIGL_COMPILE_FLAGS_CUDA -O3 -Xcompiler=-Wall,-Wextra,-Wno-unused-parameter) # --------------------------------------------------------------------------- # Extension modules — auto-discovered. @@ -91,7 +93,10 @@ foreach(_py_src IN LISTS _PYTHON_SRCS) pybind11_add_module("${_name}" ${_sources}) target_link_libraries("${_name}" PRIVATE "${TORCH_LIBRARIES}" "${TORCH_PYTHON_LIBRARY}") - target_compile_options("${_name}" PRIVATE ${GIGL_COMPILE_FLAGS}) + target_compile_options("${_name}" PRIVATE + $<$:${GIGL_COMPILE_FLAGS}> + $<$:${GIGL_COMPILE_FLAGS_CUDA}> + ) # TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. # PyTorch's own build system sets this; we must define it explicitly here. target_compile_definitions("${_name}" PRIVATE "TORCH_EXTENSION_NAME=${_name}") diff --git a/MANIFEST.in b/MANIFEST.in index f7ce04948..b53f4d2cc 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ global-exclude tests/* recursive-include gigl/deps *.jar -recursive-include gigl/csrc *.cpp *.cu *.h +recursive-include gigl/csrc *.cpp *.cu *.h *.cuh From 712d1e2638df08e3a5270f1f5757a6c37313c1ea Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 21 Apr 2026 00:10:02 +0000 Subject: [PATCH 068/148] Add additional cuda fixes --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 7867aacfb..018bd0f77 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG?=${DOCKER_IMAGE_MAIN_CPU_NAME}:${DATE} DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${DATE} PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts -CPP_SOURCES:=$(shell find gigl/csrc -name "*.cpp" -o -name "*.cu" 2>/dev/null) +CPP_SOURCES:=$(shell find gigl/csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) # clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). # Exclude .cu files from tidy targets; clang-format and clangd handle them fine. CPP_SOURCES_NO_CUDA:=$(filter-out %.cu,$(CPP_SOURCES)) @@ -119,7 +119,7 @@ check_format_md: uv run mdformat --check ${MD_FILES} check_format_cpp: - clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES) + $(if $(CPP_SOURCES),clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES)) check_format: check_format_py check_format_cpp check_format_scala check_format_md @@ -155,7 +155,7 @@ format_md: uv run mdformat ${MD_FILES} format_cpp: - clang-format-15 -i --style=file $(CPP_SOURCES) + $(if $(CPP_SOURCES),clang-format-15 -i --style=file $(CPP_SOURCES)) format: format_py format_cpp format_scala format_md @@ -175,7 +175,7 @@ check_lint_cpp: # changes expressions, adds/removes keywords), not just style. Run manually and # review the diff before committing. fix_lint_cpp: generate_compile_commands - clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES_NO_CUDA) + $(if $(CPP_SOURCES_NO_CUDA),clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES_NO_CUDA)) lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" From 2861b8d4687f9ec2a6a091c89d3a32f5cc6f4462 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 21 Apr 2026 00:52:21 +0000 Subject: [PATCH 069/148] remove no build isolation from calls, update pyproject to not build isolate gigl --- .github/workflows/release.yml | 3 +-- CMakeLists.txt | 7 +++++++ Makefile | 6 +++--- containers/Dockerfile.dataflow.src | 2 +- containers/Dockerfile.src | 2 +- gigl/orchestration/Dockerfile.customer_src | 2 +- pyproject.toml | 5 +++++ 7 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 05bf649ef..76a35448f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,11 +55,10 @@ jobs: run: | uv pip install "torch==2.8" --index-url ${{ matrix.torch-index }} --inexact - # Build without isolation so the pre-installed torch variant above is used. # The build tag (e.g. 1cpu, 1cu128) differentiates the wheel filenames so # both can coexist in the same registry index. - name: Build Whl Distribution - run: uv build --wheel --no-build-isolation -C "wheel.build-tag=1${{ matrix.torch-variant }}" + run: uv build --wheel -C "wheel.build-tag=1${{ matrix.torch-variant }}" - name: Publish Package 🚀 env: diff --git a/CMakeLists.txt b/CMakeLists.txt index 274193709..f0ed35ec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,13 @@ execute_process( ) find_package(pybind11 CONFIG REQUIRED) +# find_package(Torch) internally calls enable_language(CUDA) when torch was built with CUDA +# support, which requires CMAKE_CUDA_COMPILER to be set. Provide the standard install path +# as a hint so nvcc is found even when /usr/local/cuda/bin is not on PATH. +if(NOT CMAKE_CUDA_COMPILER) + find_program(CMAKE_CUDA_COMPILER nvcc HINTS /usr/local/cuda/bin) +endif() + # Locate PyTorch headers via its own cmake prefix path (works for both CPU and CUDA torch). execute_process( COMMAND "${Python_EXECUTABLE}" -c diff --git a/Makefile b/Makefile index 018bd0f77..0642a07e3 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ install_dev_deps: check_if_valid_env bash ./requirements/install_py_deps.sh --dev bash ./requirements/install_scala_deps.sh bash ./requirements/install_cpp_deps.sh - uv pip install -e . --no-build-isolation + uv pip install -e . uv run pre-commit install --hook-type pre-commit --hook-type pre-push # Production environments, if you are developing use `make install_dev_deps` instead @@ -62,7 +62,7 @@ install_deps: gcloud auth configure-docker us-central1-docker.pkg.dev bash ./requirements/install_py_deps.sh bash ./requirements/install_scala_deps.sh - uv pip install -e . --no-build-isolation + uv pip install -e . # These are a collection of tests that are run before anything is installed using tools available on host. # May include tests that check the sanity of the repo state i.e. ones that may even cause the failure of @@ -163,7 +163,7 @@ type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs build_cpp_extensions: - uv pip install -e . --no-build-isolation + uv pip install -e . generate_compile_commands: uv run python -m scripts.generate_compile_commands diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index 5e3c9f9e7..5ff2bd6ec 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -16,6 +16,6 @@ COPY gigl gigl COPY snapchat snapchat COPY tests tests RUN uv pip install scikit-build-core pybind11 -RUN uv pip install -e . --no-build-isolation +RUN uv pip install -e . WORKDIR / diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index c897e7465..e848bb81a 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -22,4 +22,4 @@ COPY tests tests COPY examples examples RUN uv pip install scikit-build-core pybind11 -RUN uv pip install -e . --no-build-isolation +RUN uv pip install -e . diff --git a/gigl/orchestration/Dockerfile.customer_src b/gigl/orchestration/Dockerfile.customer_src index afa3d124c..868e6279f 100644 --- a/gigl/orchestration/Dockerfile.customer_src +++ b/gigl/orchestration/Dockerfile.customer_src @@ -10,4 +10,4 @@ WORKDIR /gigl COPY . . # Find out if there is 'setup.py' or 'pyproject.toml' in the current directory, if so install it -RUN if [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then uv pip install scikit-build-core pybind11 && uv pip install -e . --no-build-isolation; fi +RUN if [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then uv pip install scikit-build-core pybind11 && uv pip install -e .; fi diff --git a/pyproject.toml b/pyproject.toml index 16a6ab30d..3d0591809 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,11 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", ] +# gigl's CMakeLists.txt requires torch headers at build time (find_package(Torch)). +# Disabling build isolation for gigl lets the build use whatever torch variant is +# already installed (CPU or CUDA), rather than downloading a fresh wheel into an +# isolated env that ignores the project's index routing. +no-build-isolation-package = ["gigl"] [dependency-groups] dev = [ From adf7046b6541609b607da81adb3d02a6118d7aff Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 21 Apr 2026 00:55:23 +0000 Subject: [PATCH 070/148] remove additional build isolations --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- .github/workflows/release-documentation.yml | 2 +- requirements/install_py_deps.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index da7fd0f4e..ecdddd120 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -29,7 +29,7 @@ steps: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes gcloud auth configure-docker us-central1-docker.pkg.dev # Install GiGL - uv pip install -e . --no-build-isolation + uv pip install -e . # The builder operates in its own user dir, usually /workspace, # so we need to copy the gigl tools dir to the current cloud_builder's user dir. # See: containers/Dockerfile.builder. diff --git a/.github/workflows/release-documentation.yml b/.github/workflows/release-documentation.yml index d6efc650d..044492888 100644 --- a/.github/workflows/release-documentation.yml +++ b/.github/workflows/release-documentation.yml @@ -45,7 +45,7 @@ jobs: - name: Install necessary doc dependencies run: | uv sync --group docs --inexact - uv pip install -e . --no-build-isolation + uv pip install -e . - name: Sphinx build run: | make build_docs diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index 3c123c5fa..f868e343f 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -139,7 +139,7 @@ install_gigl_lib_deps() { fi # --no-install-project: skip building and installing the gigl package itself here. - # The project is installed separately via `uv pip install -e . --no-build-isolation` + # The project is installed separately via `uv pip install -e .` # (see Makefile install_dev_deps/install_deps targets and the *.src Dockerfiles). # This avoids scikit-build-core requiring all source files (e.g. README.md, CMakeLists.txt) # to be present in environments that only need the dependencies (e.g. base Docker images). From 549702bc154dd0d3bb43587ed4dcb013855350bd Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 20:10:36 +0000 Subject: [PATCH 071/148] Update release --- .github/workflows/release.yml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 76a35448f..7b31768a8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,14 +13,14 @@ permissions: jobs: build: name: Build and release pip whl (${{ matrix.torch-variant }}) - runs-on: ubuntu-latest + runs-on: ${{ matrix.runner }} strategy: matrix: include: - - torch-variant: cpu - torch-index: https://download.pytorch.org/whl/cpu - - torch-variant: cu128 - torch-index: https://download.pytorch.org/whl/cu128 + - runner: ubuntu-latest + torch-variant: cpu + - runner: gigl-gpu-instances + torch-variant: cu128 env: PROJECT_ID: ${{ vars.GCP_PROJECT_ID }} environment: @@ -48,13 +48,6 @@ jobs: # Pre-install keyring and Artifact Registry plugin from the public PyPI uv tool install keyring --with keyrings.google-artifactregistry-auth==1.1.2 - # install_dev_deps auto-detects CUDA and installs the CPU torch variant on - # ubuntu-latest runners. Override here with the correct variant for this build - # so CMake picks up the right torch headers (CPU-only vs CUDA-enabled). - - name: Install torch variant for build - run: | - uv pip install "torch==2.8" --index-url ${{ matrix.torch-index }} --inexact - # The build tag (e.g. 1cpu, 1cu128) differentiates the wheel filenames so # both can coexist in the same registry index. - name: Build Whl Distribution From ba300c3ea86bc32d1392b5c5b80d06d3762ba1b3 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 21:06:29 +0000 Subject: [PATCH 072/148] Address additional cpp comments --- .clang-format | 5 +++- .clang-tidy | 5 +++- .github/workflows/on-pr-comment.yml | 7 ++--- CMakeLists.txt | 38 ++++++++++++++++++++++++++-- Makefile | 29 ++++++++++++++++----- containers/Dockerfile.dataflow.src | 2 +- containers/Dockerfile.src | 6 +---- docs/cpp_style_guide.md | 28 ++++++++++++++++++++ requirements/install_cpp_deps.sh | 11 +++++++- requirements/install_py_deps.sh | 2 -- scripts/generate_compile_commands.py | 11 ++++---- scripts/run_cpp_lint.py | 13 ++++++---- 12 files changed, 123 insertions(+), 34 deletions(-) diff --git a/.clang-format b/.clang-format index e623d7ac7..e099a8b75 100644 --- a/.clang-format +++ b/.clang-format @@ -34,6 +34,9 @@ DerivePointerAlignment: false DisableFormat: false FixNamespaceComments: true ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +# Lower Priority numbers sort first (Priority 1 appears before Priority 2, etc.). +# This is the Google/PyTorch convention — the opposite of the LLVM default. +# Result: project-local headers (1) → LLVM/clang headers (2) → system/third-party (3). IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 @@ -77,7 +80,7 @@ SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp11 +Standard: Cpp17 TabWidth: 4 UseTab: Never ... diff --git a/.clang-tidy b/.clang-tidy index 39271bca7..04b9e4eba 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -48,7 +48,6 @@ Checks: > WarningsAsErrors: '*' HeaderFilterRegex: '.*/gigl/csrc/.*' FormatStyle: none -User: jenkins # CheckOptions: per-check tuning parameters. Each entry configures a specific # option for an individual check, using the form: # key: . @@ -158,6 +157,10 @@ CheckOptions: value: llvm - key: readability-braces-around-statements.ShortStatementLines value: '0' + # BranchThreshold, NestingThreshold, and ParameterThreshold are set to UINT32_MAX + # to effectively disable these sub-checks. GNN/ML kernels legitimately have deep + # nesting (loops over nodes, edges, and features) and many parameters (model configs, + # hyperparameters), so enforcing these limits would generate noise on valid code. - key: readability-function-size.BranchThreshold value: '4294967295' - key: readability-function-size.LineThreshold diff --git a/.github/workflows/on-pr-comment.yml b/.github/workflows/on-pr-comment.yml index 1a5020ffb..53ab9b146 100644 --- a/.github/workflows/on-pr-comment.yml +++ b/.github/workflows/on-pr-comment.yml @@ -76,12 +76,9 @@ jobs: pr_number: ${{ github.event.issue.number }} should_leave_progress_comments: "true" descriptive_workflow_name: "C++ Unit Test" - setup_gcloud: "true" - use_cloud_run: "true" - gcp_project_id: ${{ vars.GCP_PROJECT_ID }} - workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} - gcp_service_account_email: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + use_cloud_run: "false" command: | + bash requirements/install_cpp_deps.sh make unit_test_cpp unit-test-scala: diff --git a/CMakeLists.txt b/CMakeLists.txt index f0ed35ec5..0dc32647b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,10 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) +endif() + # Enable CUDA only when the toolkit is present; allows the same CMakeLists.txt # to build on CPU-only machines without requiring nvcc. include(CheckLanguage) @@ -24,7 +28,11 @@ execute_process( "import pybind11; print(pybind11.get_cmake_dir())" OUTPUT_VARIABLE pybind11_DIR OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _pybind11_result ) +if(NOT _pybind11_result EQUAL 0) + message(FATAL_ERROR "Failed to locate pybind11. Run: make install_dev_deps") +endif() find_package(pybind11 CONFIG REQUIRED) # find_package(Torch) internally calls enable_language(CUDA) when torch was built with CUDA @@ -40,8 +48,15 @@ execute_process( "import torch; print(torch.utils.cmake_prefix_path)" OUTPUT_VARIABLE TORCH_CMAKE_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _torch_result ) +if(NOT _torch_result EQUAL 0) + message(FATAL_ERROR "Failed to locate torch. Run: make install_dev_deps") +endif() +# CMAKE_CUDA_ARCHITECTURES is intentionally not set here. find_package(Torch) injects +# a comprehensive -gencode arch list (via TORCH_LIBRARIES) covering all supported GPU +# generations, so setting it explicitly would duplicate or conflict with torch's flags. find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") # torch_python provides the pybind11 type casters for at::Tensor. It is not @@ -52,7 +67,11 @@ execute_process( "import torch, os; print(os.path.join(os.path.dirname(torch.__file__), 'lib'))" OUTPUT_VARIABLE TORCH_LIB_DIR OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _torch_lib_result ) +if(NOT _torch_lib_result EQUAL 0) + message(FATAL_ERROR "Failed to locate torch lib dir. Run: make install_dev_deps") +endif() find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_LIB_DIR}" REQUIRED) # Preserve torch lib dir in the installed .so RPATH so the extension loads @@ -60,9 +79,17 @@ find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_LIB_DIR}" REQUIRED set(CMAKE_INSTALL_RPATH "${TORCH_LIB_DIR}") set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -set(GIGL_COMPILE_FLAGS -O3 -Wall -Wextra -Wno-unused-parameter) +set(GIGL_COMPILE_FLAGS + $<$:-O3> + $<$:-O0 -g> + -Wall -Wextra -Wno-unused-parameter +) # nvcc does not accept bare -Wall/-Wextra; wrap them with -Xcompiler for CUDA sources. -set(GIGL_COMPILE_FLAGS_CUDA -O3 -Xcompiler=-Wall,-Wextra,-Wno-unused-parameter) +set(GIGL_COMPILE_FLAGS_CUDA + $<$:-O3> + $<$:-O0 -g> + -Xcompiler=-Wall,-Wextra,-Wno-unused-parameter +) # --------------------------------------------------------------------------- # Extension modules — auto-discovered. @@ -83,6 +110,8 @@ else() ) endif() +option(GIGL_BUILD_TESTS "Build C++ unit tests (used by make unit_test_cpp)" OFF) + foreach(_py_src IN LISTS _PYTHON_SRCS) get_filename_component(_dir "${_py_src}" DIRECTORY) get_filename_component(_stem "${_py_src}" NAME_WE) @@ -109,3 +138,8 @@ foreach(_py_src IN LISTS _PYTHON_SRCS) target_compile_definitions("${_name}" PRIVATE "TORCH_EXTENSION_NAME=${_name}") install(TARGETS "${_name}" DESTINATION "${_rel_dir}") endforeach() + +if(GIGL_BUILD_TESTS) + enable_testing() + add_subdirectory(tests/unit/cpp) +endif() diff --git a/Makefile b/Makefile index 0642a07e3..d50a85fad 100644 --- a/Makefile +++ b/Makefile @@ -99,10 +99,14 @@ unit_test_scala: clean_build_files_scala # Eventually, we should look into splitting these up. # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. -unit_test_cpp: - cmake -S tests/unit/cpp -B .cache/cpp_tests - cmake --build .cache/cpp_tests --parallel - ctest --test-dir .cache/cpp_tests --output-on-failure +CMAKE_BUILD_TYPE ?= Release +.cache/cpp_tests/.configured: CMakeLists.txt tests/unit/cpp/CMakeLists.txt + uv run cmake -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) + touch .cache/cpp_tests/.configured + +unit_test_cpp: .cache/cpp_tests/.configured + uv run cmake --build .cache/cpp_tests --parallel + uv run ctest --test-dir .cache/cpp_tests --output-on-failure unit_test: precondition_tests unit_test_py unit_test_scala unit_test_cpp @@ -162,13 +166,21 @@ format: format_py format_cpp format_scala format_md type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs -build_cpp_extensions: +# Stamp-file guard: uv pip install -e . triggers a full CMake configure-and-build +# cycle (loading torch headers) even when nothing changed. By making the stamp file +# depend on C++ sources, CMakeLists.txt, and pyproject.toml, make skips the reinstall +# on subsequent runs unless something actually changed. The stamp file lives inside +# .cache/cmake_build so it is automatically invalidated if the build dir is cleaned. +.cache/cmake_build/.gigl_built: $(shell find gigl/csrc \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) CMakeLists.txt pyproject.toml uv pip install -e . + touch .cache/cmake_build/.gigl_built + +build_cpp_extensions: .cache/cmake_build/.gigl_built generate_compile_commands: uv run python -m scripts.generate_compile_commands -check_lint_cpp: +check_lint_cpp: generate_compile_commands uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA) # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, @@ -180,6 +192,11 @@ fix_lint_cpp: generate_compile_commands lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" +# Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent +# after switching between branches with substantially different CMakeLists.txt structure. +clean_cpp: + rm -rf .cache/cpp_tests .cache/cmake_build + # compiles current working state of scala projects to local jars compile_jars: @echo "Compiling jars..." diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index 5ff2bd6ec..4b5427476 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -15,7 +15,7 @@ COPY deployment deployment COPY gigl gigl COPY snapchat snapchat COPY tests tests -RUN uv pip install scikit-build-core pybind11 +RUN uv pip install "scikit-build-core>=0.10" "pybind11>=2.12" RUN uv pip install -e . WORKDIR / diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index e848bb81a..bf3a51903 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -1,10 +1,6 @@ ARG BASE_IMAGE FROM $BASE_IMAGE -# Copy the source -WORKDIR /gigl - - # Note: main package files must live in root of the repo for the python package to be built correctly for Dataflow workers. # See https://beam.apache.org/documentation/sdks/python-pipxeline-dependencies/#create-reproducible-environments. WORKDIR /gigl @@ -21,5 +17,5 @@ COPY snapchat snapchat COPY tests tests COPY examples examples -RUN uv pip install scikit-build-core pybind11 +RUN uv pip install "scikit-build-core>=0.10" "pybind11>=2.12" RUN uv pip install -e . diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 97eb9447c..f6c3a6317 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -14,6 +14,34 @@ make format_cpp # Format all C++ files in-place make check_lint_cpp # Run clang-tidy static analysis ``` +> **Note — CUDA files (`.cu`) are excluded from clang-tidy.** +> clang-tidy 15 does not support CUDA syntax and will error on `.cu` files. The Makefile +> defines `CPP_SOURCES_NO_CUDA` (which filters out `.cu` files) and passes only that set +> to clang-tidy. If you add a new `.cu` file, it will not appear in lint output — this is +> expected. Lint coverage for CUDA files requires upgrading to a clang-tidy version with +> CUDA support. + +______________________________________________________________________ + +## Build Configuration + +The default build type is `Release` (`-O3`). To build with debug symbols (`-O0 -g`) — e.g. for stepping through +C++ code in a debugger — pass `Debug` explicitly: + +**Editable install (local development):** + +```bash +uv pip install -e . -C cmake.build-type=Debug +``` + +**C++ unit tests:** + +```bash +make unit_test_cpp CMAKE_BUILD_TYPE=Debug +``` + +To restore optimised builds, replace `Debug` with `Release`, or omit the flag (Release is the default). + ______________________________________________________________________ ## Formatting (`.clang-format`) diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 6bfb233a2..cfc40afb8 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -15,7 +15,6 @@ set -x is_running_on_mac() { [ "$(uname)" == "Darwin" ] - return $? } if is_running_on_mac; then @@ -48,7 +47,17 @@ else # headers. Without this package clang++-15 cannot find standard headers like . # clang++-15 itself is needed because generate_compile_commands.py rewrites # compile_commands.json to use it so clangd natively understands the commands. + apt-get update -y apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake + + # Verify cmake >= 3.18 (our CMakeLists.txt requires it; Ubuntu 20.04 apt provides 3.16). + # sort -V -C exits 0 if the two lines are already in ascending version order + # (i.e. 3.18 <= cmake_version), non-zero otherwise. + cmake_version=$(cmake --version | awk 'NR==1{print $3}') + if ! printf '3.18\n%s\n' "$cmake_version" | sort -V -C 2>/dev/null; then + echo "ERROR: cmake >= 3.18 required, found $cmake_version. See https://cmake.org/download/" >&2 + exit 1 + fi fi echo "Finished installing C++ tooling" diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index f868e343f..294b3dbec 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -45,12 +45,10 @@ has_cuda_driver() { is_running_on_mac() { [ "$(uname)" == "Darwin" ] - return $? } is_running_on_m1_mac() { [ "$(uname)" == "Darwin" ] && [ $(uname -m) == 'arm64' ] - return $? } ### Installation Functions ### diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index f0a39b2cc..27741132a 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -18,12 +18,13 @@ """ import json +import shlex import subprocess from pathlib import Path _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build_lint" -_COMPILE_COMMANDS: Path = _REPO_ROOT / ".cache" / "compile_commands.json" +COMPILE_COMMANDS: Path = _REPO_ROOT / ".cache" / "compile_commands.json" def write_compile_commands() -> None: @@ -49,16 +50,16 @@ def write_compile_commands() -> None: # Leave .cu entries unchanged so nvcc handles them correctly. for entry in entries: if not entry.get("file", "").endswith(".cu"): - tokens = entry["command"].split() + tokens = shlex.split(entry["command"]) tokens[0] = "clang++-15" - entry["command"] = " ".join(tokens) + entry["command"] = shlex.join(tokens) - _COMPILE_COMMANDS.write_text(json.dumps(entries, indent=2)) + COMPILE_COMMANDS.write_text(json.dumps(entries, indent=2)) def main() -> None: write_compile_commands() - print(f"Wrote {_COMPILE_COMMANDS}") + print(f"Wrote {COMPILE_COMMANDS}") if __name__ == "__main__": diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 9c2cada46..7f0bb526e 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -8,13 +8,14 @@ uv run python scripts/run_cpp_lint.py [file2.cpp] ... """ +import os import re import subprocess import sys from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path -from scripts.generate_compile_commands import _COMPILE_COMMANDS, write_compile_commands +from scripts.generate_compile_commands import COMPILE_COMMANDS # Matches real clang-tidy diagnostics emitted by clangd: # E[HH:MM:SS.mmm] [check-name] Line N: message @@ -26,7 +27,7 @@ def _check_file(source: Path) -> tuple[Path, list[str]]: [ "clangd-15", f"--check={source}", - f"--compile-commands-dir={_COMPILE_COMMANDS.parent}", + f"--compile-commands-dir={COMPILE_COMMANDS.parent}", ], capture_output=True, text=True, @@ -36,6 +37,10 @@ def _check_file(source: Path) -> tuple[Path, list[str]]: m = _DIAGNOSTIC_RE.match(line) if m: diagnostics.append(m.group(1)) + if result.returncode != 0 and not diagnostics: + diagnostics = [ + f"clangd exited with code {result.returncode} (tool error or crash)" + ] return source, diagnostics @@ -44,10 +49,8 @@ def main() -> None: if not sources: sys.exit(0) - write_compile_commands() - failures: dict[Path, list[str]] = {} - with ThreadPoolExecutor() as executor: + with ThreadPoolExecutor(max_workers=min(os.cpu_count() or 1, 8)) as executor: futures = {executor.submit(_check_file, s): s for s in sources} for future in as_completed(futures): source, diagnostics = future.result() From fc68f9db0223d3373164c84a7cd85889f06dc9be Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 21:37:05 +0000 Subject: [PATCH 073/148] cleanup --- CMakeLists.txt | 48 +++++++++++++++++----------- Makefile | 2 +- requirements/install_cpp_deps.sh | 6 ++-- scripts/generate_compile_commands.py | 20 ++++++++---- scripts/run_cpp_lint.py | 40 ++++++++--------------- tests/unit/cpp/CMakeLists.txt | 17 ++++------ 6 files changed, 68 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dc32647b..0bee60488 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,14 +9,36 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() +# CMP0104: CMake 3.18+ warns when enable_language(CUDA) is called without +# CMAKE_CUDA_ARCHITECTURES being set. Set it to OFF to tell CMake not to inject +# any -gencode flags — Torch provides a comprehensive arch list via TORCH_LIBRARIES. +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18") + cmake_policy(SET CMP0104 NEW) + set(CMAKE_CUDA_ARCHITECTURES OFF) +endif() + +# Centralise CUDA language enablement so CMAKE_CUDA_STANDARD 17 is always set +# regardless of which detection path finds the compiler. +macro(_enable_cuda) + enable_language(CUDA) + set(CMAKE_CUDA_STANDARD 17) + set(CMAKE_CUDA_STANDARD_REQUIRED ON) +endmacro() + # Enable CUDA only when the toolkit is present; allows the same CMakeLists.txt # to build on CPU-only machines without requiring nvcc. include(CheckLanguage) check_language(CUDA) if(CMAKE_CUDA_COMPILER) - enable_language(CUDA) - set(CMAKE_CUDA_STANDARD 17) - set(CMAKE_CUDA_STANDARD_REQUIRED ON) + _enable_cuda() +else() + # find_package(Torch) internally calls enable_language(CUDA) when torch was built with + # CUDA support, which requires CMAKE_CUDA_COMPILER to be set. Provide the standard + # install path as a hint so nvcc is found even when /usr/local/cuda/bin is not on PATH. + find_program(CMAKE_CUDA_COMPILER nvcc HINTS /usr/local/cuda/bin) + if(CMAKE_CUDA_COMPILER) + _enable_cuda() + endif() endif() find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) @@ -35,13 +57,6 @@ if(NOT _pybind11_result EQUAL 0) endif() find_package(pybind11 CONFIG REQUIRED) -# find_package(Torch) internally calls enable_language(CUDA) when torch was built with CUDA -# support, which requires CMAKE_CUDA_COMPILER to be set. Provide the standard install path -# as a hint so nvcc is found even when /usr/local/cuda/bin is not on PATH. -if(NOT CMAKE_CUDA_COMPILER) - find_program(CMAKE_CUDA_COMPILER nvcc HINTS /usr/local/cuda/bin) -endif() - # Locate PyTorch headers via its own cmake prefix path (works for both CPU and CUDA torch). execute_process( COMMAND "${Python_EXECUTABLE}" -c @@ -54,9 +69,6 @@ if(NOT _torch_result EQUAL 0) message(FATAL_ERROR "Failed to locate torch. Run: make install_dev_deps") endif() -# CMAKE_CUDA_ARCHITECTURES is intentionally not set here. find_package(Torch) injects -# a comprehensive -gencode arch list (via TORCH_LIBRARIES) covering all supported GPU -# generations, so setting it explicitly would duplicate or conflict with torch's flags. find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") # torch_python provides the pybind11 type casters for at::Tensor. It is not @@ -81,13 +93,13 @@ set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(GIGL_COMPILE_FLAGS $<$:-O3> - $<$:-O0 -g> + $<$:-O0;-g> -Wall -Wextra -Wno-unused-parameter ) # nvcc does not accept bare -Wall/-Wextra; wrap them with -Xcompiler for CUDA sources. set(GIGL_COMPILE_FLAGS_CUDA $<$:-O3> - $<$:-O0 -g> + $<$:-O0;-g> -Xcompiler=-Wall,-Wextra,-Wno-unused-parameter ) @@ -101,12 +113,12 @@ set(GIGL_COMPILE_FLAGS_CUDA if(CMAKE_CUDA_COMPILER) file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cpp" - "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cu" + "${CMAKE_SOURCE_DIR}/gigl/csrc/python_*.cpp" + "${CMAKE_SOURCE_DIR}/gigl/csrc/python_*.cu" ) else() file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/gigl/csrc/**/python_*.cpp" + "${CMAKE_SOURCE_DIR}/gigl/csrc/python_*.cpp" ) endif() diff --git a/Makefile b/Makefile index d50a85fad..61b39f3ee 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${D PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts CPP_SOURCES:=$(shell find gigl/csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) # clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). -# Exclude .cu files from tidy targets; clang-format and clangd handle them fine. +# Exclude .cu files from tidy targets; clang-format handles them fine. CPP_SOURCES_NO_CUDA:=$(filter-out %.cu,$(CPP_SOURCES)) PY_TEST_FILES?="*_test.py" # You can override GIGL_TEST_DEFAULT_RESOURCE_CONFIG by setting it in your environment i.e. diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index cfc40afb8..cec635b71 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -41,12 +41,14 @@ if is_running_on_mac; then else # On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly # into /usr/bin. No PATH changes are needed since /usr/bin is already on PATH. - # Callers use the versioned names (clang-format-15, clang-tidy-15, clangd-15) - # directly so the version is explicit and greppable across the codebase. + # Callers use the versioned names (clang-format-15, clang-tidy-15) directly so + # the version is explicit and greppable across the codebase. # clang++-15 requires libstdc++-12-dev: on Ubuntu 22.04, clang++-15 looks for GCC 12 # headers. Without this package clang++-15 cannot find standard headers like . # clang++-15 itself is needed because generate_compile_commands.py rewrites # compile_commands.json to use it so clangd natively understands the commands. + # clangd-15 is installed for IDE language-server support (e.g. VS Code); CI lint + # uses clang-tidy-15 directly via run_cpp_lint.py. apt-get update -y apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 27741132a..0ae3ae3c8 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -5,11 +5,12 @@ The build uses the system C++ compiler (g++) so that cmake, nvcc, and Torch's cmake work without issues. After cmake writes compile_commands.json, the -compiler in each entry is replaced with ``clang++-15`` so that clangd natively -understands the commands without needing a ``--query-driver`` workaround. +compiler in each entry is replaced with ``clang++-15`` so that clangd (IDE +language server) and clang-tidy-15 (CI lint) natively understand the commands +without needing a ``--query-driver`` workaround. -Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and -by ``make generate_compile_commands`` when you need to refresh the database +Primary use: called by ``run_cpp_lint.py`` before running clang-tidy checks, +and by ``make generate_compile_commands`` when you need to refresh the database manually (e.g. after adding new source files or changing compiler flags). Usage:: @@ -48,11 +49,16 @@ def write_compile_commands() -> None: # Replace the compiler for .cpp entries with clang++-15 so clangd uses # clang-native implicit include paths instead of guessing GCC's. # Leave .cu entries unchanged so nvcc handles them correctly. + # The spec allows either "command" (string, Makefile generator) or + # "arguments" (array, Ninja generator); handle both. for entry in entries: if not entry.get("file", "").endswith(".cu"): - tokens = shlex.split(entry["command"]) - tokens[0] = "clang++-15" - entry["command"] = shlex.join(tokens) + if "command" in entry: + tokens = shlex.split(entry["command"]) + tokens[0] = "clang++-15" + entry["command"] = shlex.join(tokens) + elif "arguments" in entry: + entry["arguments"][0] = "clang++-15" COMPILE_COMMANDS.write_text(json.dumps(entries, indent=2)) diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 7f0bb526e..9b4dcdabd 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -1,6 +1,6 @@ -"""Run C++ lint on source files using clangd. +"""Run C++ lint on source files using clang-tidy. -Generates compile_commands.json, then runs clangd --check on each file in +Generates compile_commands.json, then runs clang-tidy-15 on each file in parallel and prints a clean summary. Usage:: @@ -9,7 +9,6 @@ """ import os -import re import subprocess import sys from concurrent.futures import ThreadPoolExecutor, as_completed @@ -17,31 +16,18 @@ from scripts.generate_compile_commands import COMPILE_COMMANDS -# Matches real clang-tidy diagnostics emitted by clangd: -# E[HH:MM:SS.mmm] [check-name] Line N: message -_DIAGNOSTIC_RE = re.compile(r"^E\[[\d:.]+\] (\[.+\] .+)$") - -def _check_file(source: Path) -> tuple[Path, list[str]]: +def _check_file(source: Path) -> tuple[Path, str, int]: result = subprocess.run( [ - "clangd-15", - f"--check={source}", - f"--compile-commands-dir={COMPILE_COMMANDS.parent}", + "clang-tidy-15", + f"-p={COMPILE_COMMANDS}", + str(source), ], capture_output=True, text=True, ) - diagnostics: list[str] = [] - for line in result.stderr.splitlines(): - m = _DIAGNOSTIC_RE.match(line) - if m: - diagnostics.append(m.group(1)) - if result.returncode != 0 and not diagnostics: - diagnostics = [ - f"clangd exited with code {result.returncode} (tool error or crash)" - ] - return source, diagnostics + return source, (result.stdout + result.stderr).strip(), result.returncode def main() -> None: @@ -49,21 +35,21 @@ def main() -> None: if not sources: sys.exit(0) - failures: dict[Path, list[str]] = {} + failures: dict[Path, str] = {} with ThreadPoolExecutor(max_workers=min(os.cpu_count() or 1, 8)) as executor: futures = {executor.submit(_check_file, s): s for s in sources} for future in as_completed(futures): - source, diagnostics = future.result() - if diagnostics: - failures[source] = diagnostics + source, output, returncode = future.result() + if returncode != 0: + failures[source] = output if not failures: print("\033[32mC++ lint passed.\033[0m") else: for source in sorted(failures): print(f" FAIL {source}") - for d in failures[source]: - print(f" {d}") + if failures[source]: + print(failures[source]) print( "\nRun \033[1mmake fix_lint_cpp\033[0m to auto-fix violations where possible." ) diff --git a/tests/unit/cpp/CMakeLists.txt b/tests/unit/cpp/CMakeLists.txt index 4fd05b316..10b9520cf 100644 --- a/tests/unit/cpp/CMakeLists.txt +++ b/tests/unit/cpp/CMakeLists.txt @@ -1,10 +1,3 @@ -cmake_minimum_required(VERSION 3.18) -project(GiGLCppTests CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - include(CheckLanguage) check_language(CUDA) if(CMAKE_CUDA_COMPILER) @@ -21,6 +14,7 @@ FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.14.0 + GIT_SHALLOW TRUE ) # Prevent GoogleTest from overriding the compiler's runtime on Windows # (no-op on Linux/Mac, but required for portable CMake config). @@ -44,9 +38,12 @@ else() endif() foreach(test_source ${TEST_SOURCES}) - # Derive the binary name from the filename, e.g.: - # ppr_forward_push_test.cpp → ppr_forward_push_test - get_filename_component(test_name ${test_source} NAME_WE) + # Derive a unique binary name from the path relative to this directory, e.g.: + # ppr_forward_push_test.cpp → ppr_forward_push_test + # sampling/ppr_forward_push_test.cpp → sampling_ppr_forward_push_test + file(RELATIVE_PATH _rel "${CMAKE_CURRENT_SOURCE_DIR}" "${test_source}") + string(REPLACE "/" "_" test_name "${_rel}") + string(REGEX REPLACE "\\.[^.]+$" "" test_name "${test_name}") add_executable(${test_name} ${test_source}) target_link_libraries(${test_name} GTest::gtest_main) # add_test registers the binary with CTest. Each *_test binary is one From fa1ee91259179a57c11d41275e48a89eeec80225 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 21:52:33 +0000 Subject: [PATCH 074/148] Updates --- .clang-format | 4 ++-- .clang-tidy | 2 +- docs/cpp_style_guide.md | 2 +- requirements/install_cpp_deps.sh | 12 ++++-------- scripts/generate_compile_commands.py | 9 ++++----- tests/unit/cpp/infrastructure_test.cpp | 1 - 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/.clang-format b/.clang-format index e099a8b75..1d37147c7 100644 --- a/.clang-format +++ b/.clang-format @@ -44,7 +44,7 @@ IncludeCategories: Priority: 3 - Regex: '.*' Priority: 1 -IncludeIsMainRegex: '$' +IncludeIsMainRegex: '^$' IndentCaseLabels: true IndentWidth: 4 IndentWrappedFunctionNames: false @@ -80,7 +80,7 @@ SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp17 +Standard: c++17 TabWidth: 4 UseTab: Never ... diff --git a/.clang-tidy b/.clang-tidy index 04b9e4eba..250d06ef6 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -110,7 +110,7 @@ CheckOptions: - key: modernize-loop-convert.MinConfidence value: reasonable - key: modernize-loop-convert.NamingStyle - value: CamelCase + value: camelBack - key: modernize-loop-convert.UseCxx20ReverseRanges value: '0' - key: modernize-make-unique.IgnoreMacros diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index f6c3a6317..a4097cc9b 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -176,7 +176,7 @@ Enforced via `readability-identifier-naming`: | `HeaderFilterRegex` | `.*/gigl/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | | `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | | `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | -| `modernize-loop-convert.NamingStyle` | `CamelCase` | Auto-generated loop variable names use CamelCase | +| `modernize-loop-convert.NamingStyle` | `camelBack` | Auto-generated loop variable names use camelBack, matching `readability-identifier-naming.VariableCase` | | `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | | `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index cec635b71..3ecff18ce 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -30,13 +30,11 @@ if is_running_on_mac; then for rc_file in ~/.zshrc ~/.bashrc; do if [ -f "$rc_file" ] && ! grep -qF "$LLVM_BIN" "$rc_file"; then printf '\n# Added by GiGL install_cpp_deps.sh\nexport PATH="%s:$PATH"\n' "$LLVM_BIN" >> "$rc_file" - echo "Added LLVM bin to PATH in $rc_file" + echo "NOTE: Added LLVM bin to PATH in $rc_file." + echo " Open a new terminal (or run: source $rc_file) to pick up the change." fi done - # NOTE: this export only affects subprocesses of this script, not the calling - # shell or make process. Open a new terminal (or run `source ~/.zshrc`) after - # install_dev_deps to pick up the PATH change. export PATH="$LLVM_BIN:$PATH" else # On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly @@ -46,11 +44,9 @@ else # clang++-15 requires libstdc++-12-dev: on Ubuntu 22.04, clang++-15 looks for GCC 12 # headers. Without this package clang++-15 cannot find standard headers like . # clang++-15 itself is needed because generate_compile_commands.py rewrites - # compile_commands.json to use it so clangd natively understands the commands. - # clangd-15 is installed for IDE language-server support (e.g. VS Code); CI lint - # uses clang-tidy-15 directly via run_cpp_lint.py. + # compile_commands.json to use it so clang-tidy natively understands the commands. apt-get update -y - apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake + apt-get install -y clang-format-15 clang-tidy-15 clang++-15 libstdc++-12-dev cmake # Verify cmake >= 3.18 (our CMakeLists.txt requires it; Ubuntu 20.04 apt provides 3.16). # sort -V -C exits 0 if the two lines are already in ascending version order diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 0ae3ae3c8..a3bb7ca70 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -1,13 +1,12 @@ -"""Generate .cache/compile_commands.json for clangd. +"""Generate .cache/compile_commands.json for clang-tidy. Delegates to CMake (which already knows all include paths and compiler flags via find_package(Torch)) rather than manually constructing the database. The build uses the system C++ compiler (g++) so that cmake, nvcc, and Torch's cmake work without issues. After cmake writes compile_commands.json, the -compiler in each entry is replaced with ``clang++-15`` so that clangd (IDE -language server) and clang-tidy-15 (CI lint) natively understand the commands -without needing a ``--query-driver`` workaround. +compiler in each entry is replaced with ``clang++-15`` so that clang-tidy +natively understands the commands without needing a ``--query-driver`` workaround. Primary use: called by ``run_cpp_lint.py`` before running clang-tidy checks, and by ``make generate_compile_commands`` when you need to refresh the database @@ -46,7 +45,7 @@ def write_compile_commands() -> None: raw_path = _CMAKE_BUILD_DIR / "compile_commands.json" entries: list[dict] = json.loads(raw_path.read_text()) - # Replace the compiler for .cpp entries with clang++-15 so clangd uses + # Replace the compiler for .cpp entries with clang++-15 so clang-tidy uses # clang-native implicit include paths instead of guessing GCC's. # Leave .cu entries unchanged so nvcc handles them correctly. # The spec allows either "command" (string, Makefile generator) or diff --git a/tests/unit/cpp/infrastructure_test.cpp b/tests/unit/cpp/infrastructure_test.cpp index af85a6660..eb3c1aa3d 100644 --- a/tests/unit/cpp/infrastructure_test.cpp +++ b/tests/unit/cpp/infrastructure_test.cpp @@ -9,5 +9,4 @@ // the build environment itself. TEST(PlaceholderTest, BasicArithmetic) { EXPECT_EQ(1 + 1, 2); - EXPECT_NE(1 + 1, 3); } From 267d0cc2136f3dcc69bad027c2db17899faaa205 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 22:02:04 +0000 Subject: [PATCH 075/148] Fix --- gigl/distributed/dist_ppr_sampler.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 525c6379a..0e4290c58 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -465,9 +465,9 @@ async def _compute_ppr_scores( ntype_to_flat_weights[ntype] = flat_weights.to(device) ntype_to_valid_counts[ntype] = valid_counts.to(device) - nodes_drained_per_iteration: list[ - int - ] = ppr_state.get_nodes_drained_per_iteration() + nodes_drained_per_iteration: list[int] = ( + ppr_state.get_nodes_drained_per_iteration() + ) timing = ( total_fetch_ms, total_push_ms, From bb87166815ad7514442c234cb9151375d848faa7 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 22:02:19 +0000 Subject: [PATCH 076/148] Update --- Makefile | 4 +-- requirements/install_cpp_deps.sh | 8 ++--- scripts/generate_compile_commands.py | 12 +++---- scripts/run_cpp_lint.py | 47 ++++++++++++++++++++-------- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 61b39f3ee..037e389e0 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${D PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts CPP_SOURCES:=$(shell find gigl/csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) # clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). -# Exclude .cu files from tidy targets; clang-format handles them fine. +# Exclude .cu files from tidy targets; clang-format and clangd handle them fine. CPP_SOURCES_NO_CUDA:=$(filter-out %.cu,$(CPP_SOURCES)) PY_TEST_FILES?="*_test.py" # You can override GIGL_TEST_DEFAULT_RESOURCE_CONFIG by setting it in your environment i.e. @@ -195,7 +195,7 @@ lint_test: check_format assert_yaml_configs_parse check_lint_cpp # Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent # after switching between branches with substantially different CMakeLists.txt structure. clean_cpp: - rm -rf .cache/cpp_tests .cache/cmake_build + rm -rf .cache/cpp_tests .cache/cmake_build .cache/cmake_build_lint # compiles current working state of scala projects to local jars compile_jars: diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 3ecff18ce..a5f2f3857 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -39,14 +39,14 @@ if is_running_on_mac; then else # On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly # into /usr/bin. No PATH changes are needed since /usr/bin is already on PATH. - # Callers use the versioned names (clang-format-15, clang-tidy-15) directly so - # the version is explicit and greppable across the codebase. + # Callers use the versioned names (clang-format-15, clang-tidy-15, clangd-15) + # directly so the version is explicit and greppable across the codebase. # clang++-15 requires libstdc++-12-dev: on Ubuntu 22.04, clang++-15 looks for GCC 12 # headers. Without this package clang++-15 cannot find standard headers like . # clang++-15 itself is needed because generate_compile_commands.py rewrites - # compile_commands.json to use it so clang-tidy natively understands the commands. + # compile_commands.json to use it so clangd natively understands the commands. apt-get update -y - apt-get install -y clang-format-15 clang-tidy-15 clang++-15 libstdc++-12-dev cmake + apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake # Verify cmake >= 3.18 (our CMakeLists.txt requires it; Ubuntu 20.04 apt provides 3.16). # sort -V -C exits 0 if the two lines are already in ascending version order diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index a3bb7ca70..3396cf369 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -1,15 +1,15 @@ -"""Generate .cache/compile_commands.json for clang-tidy. +"""Generate .cache/compile_commands.json for clangd. Delegates to CMake (which already knows all include paths and compiler flags via find_package(Torch)) rather than manually constructing the database. The build uses the system C++ compiler (g++) so that cmake, nvcc, and Torch's cmake work without issues. After cmake writes compile_commands.json, the -compiler in each entry is replaced with ``clang++-15`` so that clang-tidy -natively understands the commands without needing a ``--query-driver`` workaround. +compiler in each entry is replaced with ``clang++-15`` so that clangd natively +understands the commands without needing a ``--query-driver`` workaround. -Primary use: called by ``run_cpp_lint.py`` before running clang-tidy checks, -and by ``make generate_compile_commands`` when you need to refresh the database +Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and +by ``make generate_compile_commands`` when you need to refresh the database manually (e.g. after adding new source files or changing compiler flags). Usage:: @@ -45,7 +45,7 @@ def write_compile_commands() -> None: raw_path = _CMAKE_BUILD_DIR / "compile_commands.json" entries: list[dict] = json.loads(raw_path.read_text()) - # Replace the compiler for .cpp entries with clang++-15 so clang-tidy uses + # Replace the compiler for .cpp entries with clang++-15 so clangd uses # clang-native implicit include paths instead of guessing GCC's. # Leave .cu entries unchanged so nvcc handles them correctly. # The spec allows either "command" (string, Makefile generator) or diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 9b4dcdabd..7400380b1 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -1,6 +1,6 @@ -"""Run C++ lint on source files using clang-tidy. +"""Run C++ lint on source files using clangd. -Generates compile_commands.json, then runs clang-tidy-15 on each file in +Generates compile_commands.json, then runs clangd --check on each file in parallel and prints a clean summary. Usage:: @@ -9,6 +9,7 @@ """ import os +import re import subprocess import sys from concurrent.futures import ThreadPoolExecutor, as_completed @@ -16,18 +17,38 @@ from scripts.generate_compile_commands import COMPILE_COMMANDS +# Matches real clang-tidy diagnostics emitted by clangd: +# E[HH:MM:SS.mmm] [check-name] Line N: message +_DIAGNOSTIC_RE = re.compile(r"^E\[[\d:.]+\] (\[.+\] .+)$") -def _check_file(source: Path) -> tuple[Path, str, int]: + +def _check_file(source: Path) -> tuple[Path, list[str]]: result = subprocess.run( [ - "clang-tidy-15", - f"-p={COMPILE_COMMANDS}", - str(source), + "clangd-15", + f"--check={source}", + f"--compile-commands-dir={COMPILE_COMMANDS.parent}", ], capture_output=True, text=True, ) - return source, (result.stdout + result.stderr).strip(), result.returncode + diagnostics: list[str] = [] + completed_normally = False + for line in result.stderr.splitlines(): + if "All checks completed" in line: + completed_normally = True + m = _DIAGNOSTIC_RE.match(line) + if m: + diagnostics.append(m.group(1)) + # Only treat a non-zero exit as a crash if clangd didn't reach its normal + # completion message. A non-zero exit with "All checks completed" means + # clangd found only IDE-action probe failures (tweak: ... ==> FAIL), which + # are not lint violations and should be ignored. + if not completed_normally and result.returncode != 0: + diagnostics = [ + f"clangd exited with code {result.returncode} (tool error or crash)" + ] + return source, diagnostics def main() -> None: @@ -35,21 +56,21 @@ def main() -> None: if not sources: sys.exit(0) - failures: dict[Path, str] = {} + failures: dict[Path, list[str]] = {} with ThreadPoolExecutor(max_workers=min(os.cpu_count() or 1, 8)) as executor: futures = {executor.submit(_check_file, s): s for s in sources} for future in as_completed(futures): - source, output, returncode = future.result() - if returncode != 0: - failures[source] = output + source, diagnostics = future.result() + if diagnostics: + failures[source] = diagnostics if not failures: print("\033[32mC++ lint passed.\033[0m") else: for source in sorted(failures): print(f" FAIL {source}") - if failures[source]: - print(failures[source]) + for d in failures[source]: + print(f" {d}") print( "\nRun \033[1mmake fix_lint_cpp\033[0m to auto-fix violations where possible." ) From 907fc1208de3010637dec39483d4b160d752b5b2 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 22:22:32 +0000 Subject: [PATCH 077/148] continued updates --- .clang-format | 2 +- .clang-tidy | 4 ++++ .github/workflows/release.yml | 4 ++-- CMakeLists.txt | 4 ---- Makefile | 2 +- requirements/install_cpp_deps.sh | 3 +++ scripts/generate_compile_commands.py | 12 +++++++++--- scripts/run_cpp_lint.py | 6 ++++-- 8 files changed, 24 insertions(+), 13 deletions(-) diff --git a/.clang-format b/.clang-format index 1d37147c7..8320738ea 100644 --- a/.clang-format +++ b/.clang-format @@ -76,7 +76,7 @@ SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false -SpacesInContainerLiterals: true +SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false diff --git a/.clang-tidy b/.clang-tidy index 250d06ef6..8169ebed3 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,8 @@ --- +# -bugprone-implicit-widening-of-multiplication-result is disabled because it +# crashes clang-tidy 15 on a construct in ATen/core/dynamic_type.h (upstream +# LLVM bug). Re-enable when upgrading past clang-tidy 15. +# All other disabled checks are documented in docs/cpp_style_guide.md. Checks: > boost-use-to-string, bugprone-*, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b31768a8..c9cd8c5be 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,5 +65,5 @@ jobs: if: always() # Clean up files created during Publish Package step. run: | - rm -rf ~/.pypirc - rm -rf ~/.pip/pip.conf + rm -f ~/.pypirc + rm -f ~/.pip/pip.conf diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bee60488..0de039386 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,10 +86,6 @@ if(NOT _torch_lib_result EQUAL 0) endif() find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_LIB_DIR}" REQUIRED) -# Preserve torch lib dir in the installed .so RPATH so the extension loads -# libtorch.so without requiring `import torch` to pre-populate the symbol table. -set(CMAKE_INSTALL_RPATH "${TORCH_LIB_DIR}") -set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(GIGL_COMPILE_FLAGS $<$:-O3> diff --git a/Makefile b/Makefile index 037e389e0..7a51514f2 100644 --- a/Makefile +++ b/Makefile @@ -181,7 +181,7 @@ generate_compile_commands: uv run python -m scripts.generate_compile_commands check_lint_cpp: generate_compile_commands - uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA) + $(if $(CPP_SOURCES_NO_CUDA),uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA)) # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, # changes expressions, adds/removes keywords), not just style. Run manually and diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index a5f2f3857..cb3f2d815 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -49,6 +49,9 @@ else apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake # Verify cmake >= 3.18 (our CMakeLists.txt requires it; Ubuntu 20.04 apt provides 3.16). + # sort -V (version sort) is a GNU extension only available on Linux — this block is + # intentionally inside the Linux branch; the macOS branch installs cmake via Homebrew + # which always provides a sufficiently recent version. # sort -V -C exits 0 if the two lines are already in ascending version order # (i.e. 3.18 <= cmake_version), non-zero otherwise. cmake_version=$(cmake --version | awk 'NR==1{print $3}') diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 3396cf369..1d9462d25 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -21,6 +21,7 @@ import shlex import subprocess from pathlib import Path +from typing import Any _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build_lint" @@ -30,7 +31,7 @@ def write_compile_commands() -> None: """Run CMake to generate .cache/compile_commands.json.""" _CMAKE_BUILD_DIR.mkdir(parents=True, exist_ok=True) - subprocess.run( + result = subprocess.run( [ "cmake", "-S", @@ -39,11 +40,16 @@ def write_compile_commands() -> None: str(_CMAKE_BUILD_DIR), "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", ], - check=True, + capture_output=True, + text=True, ) + if result.returncode != 0: + raise RuntimeError( + f"CMake configure failed (exit {result.returncode}):\n{result.stderr}" + ) raw_path = _CMAKE_BUILD_DIR / "compile_commands.json" - entries: list[dict] = json.loads(raw_path.read_text()) + entries: list[dict[str, Any]] = json.loads(raw_path.read_text()) # Replace the compiler for .cpp entries with clang++-15 so clangd uses # clang-native implicit include paths instead of guessing GCC's. diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 7400380b1..92c6c633c 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -1,7 +1,9 @@ """Run C++ lint on source files using clangd. -Generates compile_commands.json, then runs clangd --check on each file in -parallel and prints a clean summary. +Runs clangd --check on each file in parallel and prints a clean summary. +Expects compile_commands.json to already exist at .cache/compile_commands.json; +call ``make generate_compile_commands`` first if it is absent or stale +(``make check_lint_cpp`` does this automatically via a Makefile prerequisite). Usage:: From 056a3b4ac67f7c2507235536d361463609992546 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 23:13:11 +0000 Subject: [PATCH 078/148] Update comment --- gigl/csrc/sampling/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gigl/csrc/sampling/__init__.py b/gigl/csrc/sampling/__init__.py index b2e23ba6c..5c8b47393 100644 --- a/gigl/csrc/sampling/__init__.py +++ b/gigl/csrc/sampling/__init__.py @@ -2,8 +2,10 @@ from gigl.csrc.sampling.ppr_forward_push import PPRForwardPushState except ImportError as e: raise ImportError( - "PPR C++ extension not compiled. " - "Run `make build_cpp_extensions` from the GiGL root to build it." + f"Failed to import PPR C++ extension: {e}. " + "If the extension is not yet compiled, run `make build_cpp_extensions` from the GiGL root. " + "If it is compiled, ensure `import torch` is called before importing this module " + "so that libtorch shared libraries are loaded into the process first." ) from e __all__ = ["PPRForwardPushState"] From d0791131a4b7bcd6bab5e558ac6762b753433171 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 22 Apr 2026 23:13:22 +0000 Subject: [PATCH 079/148] Updates --- .clang-format | 5 +-- .github/workflows/on-pr-merge.yml | 10 ++++++ .github/workflows/release.yml | 23 +++++------- Makefile | 9 ++++- containers/Dockerfile.dataflow.src | 3 ++ containers/Dockerfile.src | 3 ++ docs/cpp_style_guide.md | 35 +++++++++++-------- .../getting_started/installation.md | 8 +++-- pyproject.toml | 16 ++++++++- scripts/run_cpp_lint.py | 7 ++-- 10 files changed, 80 insertions(+), 39 deletions(-) diff --git a/.clang-format b/.clang-format index 8320738ea..d064de8a0 100644 --- a/.clang-format +++ b/.clang-format @@ -36,9 +36,10 @@ FixNamespaceComments: true ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] # Lower Priority numbers sort first (Priority 1 appears before Priority 2, etc.). # This is the Google/PyTorch convention — the opposite of the LLVM default. -# Result: project-local headers (1) → LLVM/clang headers (2) → system/third-party (3). +# Result: project-local headers (1) → torch/pybind11 (2) → system/third-party (3). +# Add graphlearn_torch to the Priority 2 regex when GLT headers appear in the codebase. IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + - Regex: '^<(torch|pybind11)/' Priority: 2 - Regex: '^(<|"(gtest|isl|json)/)' Priority: 3 diff --git a/.github/workflows/on-pr-merge.yml b/.github/workflows/on-pr-merge.yml index 0e1f9ddd0..68ce947f9 100644 --- a/.github/workflows/on-pr-merge.yml +++ b/.github/workflows/on-pr-merge.yml @@ -70,6 +70,16 @@ jobs: service_account: ${{ secrets.gcp_service_account_email }} project: ${{ vars.GCP_PROJECT_ID }} + ci-unit-test-cpp: + if: github.event_name == 'merge_group' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install C++ dependencies + run: bash requirements/install_cpp_deps.sh + - name: Run C++ Unit Tests + run: make unit_test_cpp + ci-integration-test: if: github.event_name == 'merge_group' runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c9cd8c5be..dbe427863 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,10 @@ name: Release GiGL +# TODO: Before the first release using this workflow, complete the following one-time GCP setup: +# 1. Create the `gigl-cu128` Artifact Registry Python repository in GCP project +# `external-snap-ci-github-gigl` (the CPU registry `gigl` already exists). +# 2. Grant the release service account write access to the new `gigl-cu128` repository. + on: # Triggers the workflow manually for now until we have full support for releasing: # - building and releasing docker images @@ -19,8 +24,10 @@ jobs: include: - runner: ubuntu-latest torch-variant: cpu + index-name: gcp-release-registry-cpu - runner: gigl-gpu-instances torch-variant: cu128 + index-name: gcp-release-registry-cu128 env: PROJECT_ID: ${{ vars.GCP_PROJECT_ID }} environment: @@ -48,22 +55,10 @@ jobs: # Pre-install keyring and Artifact Registry plugin from the public PyPI uv tool install keyring --with keyrings.google-artifactregistry-auth==1.1.2 - # The build tag (e.g. 1cpu, 1cu128) differentiates the wheel filenames so - # both can coexist in the same registry index. - name: Build Whl Distribution - run: uv build --wheel -C "wheel.build-tag=1${{ matrix.torch-variant }}" + run: uv build --wheel - name: Publish Package 🚀 - env: - PYPIRC_CONTENTS: ${{ secrets.PYPIRC_CONTENTS }} - PIP_CONF_CONTENTS: ${{ secrets.PIP_CONF_CONTENTS }} # We upload the build whls to Google Artifact Registry. run: | - uv publish --index gcp-release-registry --username oauth2accesstoken --keyring-provider subprocess - - - name: Post Publish Package - if: always() - # Clean up files created during Publish Package step. - run: | - rm -f ~/.pypirc - rm -f ~/.pip/pip.conf + uv publish --index ${{ matrix.index-name }} --username oauth2accesstoken --keyring-provider subprocess diff --git a/Makefile b/Makefile index 7a51514f2..6e0b4c7e7 100644 --- a/Makefile +++ b/Makefile @@ -122,9 +122,15 @@ check_format_md: @echo "Checking markdown files..." uv run mdformat --check ${MD_FILES} +# TODO: Remove the $(if ...) guards in check_format_cpp, format_cpp, check_lint_cpp, and +# fix_lint_cpp once C++ source files are permanently present in the repo. The guards exist +# to silently no-op on branches that have no python_*.cpp files yet; once there is always +# at least one C++ source, the guards just hide accidental empty-source mistakes. check_format_cpp: $(if $(CPP_SOURCES),clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES)) +# Checks formatting only (clang-format, black, scalafmt, mdformat). Does NOT run +# clang-tidy static analysis — use `make check_lint_cpp` for that. check_format: check_format_py check_format_cpp check_format_scala check_format_md # Set PY_TEST_FILES= to test a specifc file. @@ -185,7 +191,8 @@ check_lint_cpp: generate_compile_commands # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, # changes expressions, adds/removes keywords), not just style. Run manually and -# review the diff before committing. +# review the diff before committing. Note: --fix cannot auto-repair every check; +# some violations require manual edits. fix_lint_cpp: generate_compile_commands $(if $(CPP_SOURCES_NO_CUDA),clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES_NO_CUDA)) diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index 4b5427476..da2be29dd 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -5,6 +5,9 @@ FROM $BASE_IMAGE # Copy the source WORKDIR /gigl +# scikit-build-core needs CMakeLists.txt (build definition), MANIFEST.in (sdist source list), +# and README.md (required by pyproject.toml's readme field) before `uv pip install -e .` +# triggers the CMake build. Without these, the install will error at configure time. COPY CMakeLists.txt CMakeLists.txt COPY MANIFEST.in MANIFEST.in COPY README.md README.md diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index bf3a51903..55b4eeee1 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -5,6 +5,9 @@ FROM $BASE_IMAGE # See https://beam.apache.org/documentation/sdks/python-pipxeline-dependencies/#create-reproducible-environments. WORKDIR /gigl +# scikit-build-core needs CMakeLists.txt (build definition), MANIFEST.in (sdist source list), +# and README.md (required by pyproject.toml's readme field) before `uv pip install -e .` +# triggers the CMake build. Without these, the install will error at configure time. COPY CMakeLists.txt CMakeLists.txt COPY MANIFEST.in MANIFEST.in COPY README.md README.md diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index a4097cc9b..434a67d4b 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -10,8 +10,9 @@ All clang-tidy warnings are treated as errors. ## Running the Tools ```bash -make format_cpp # Format all C++ files in-place -make check_lint_cpp # Run clang-tidy static analysis +make format_cpp # Format all C++ files in-place (clang-format) +make check_format_cpp # Check formatting without modifying (clang-format only, not lint) +make check_lint_cpp # Run clang-tidy static analysis ``` > **Note — CUDA files (`.cu`) are excluded from clang-tidy.** @@ -98,11 +99,13 @@ header. Includes are sorted and split into three priority groups: -| Priority | Pattern | Group | -| -------- | ------------------------------------ | ------------------------------------- | -| 1 | `.*` | Local project headers (first) | -| 2 | `^"(llvm\|llvm-c\|clang\|clang-c)/"` | LLVM/Clang internal headers | -| 3 | `^(<\|"(gtest\|isl\|json)/)` | System and third-party headers (last) | +| Priority | Pattern | Group | +| -------- | ---------------------------- | -------------------------------------------- | +| 1 | `.*` | Local project headers (first) | +| 2 | `^<(torch\|pybind11)/` | Torch and pybind11 headers | +| 3 | `^(<\|"(gtest\|isl\|json)/)` | System and other third-party headers (last) | + +> When GLT (`graphlearn_torch`) headers are added, include `graphlearn_torch` in the Priority 2 pattern. ### Raw string formatting @@ -159,14 +162,16 @@ this codebase: Enforced via `readability-identifier-naming`: -| Identifier kind | Convention | Example | -| --------------------------------------------------------- | --------------------------- | ----------------- | -| Classes, enums, unions | `CamelCase` | `DistDataset` | -| Type template parameters | `CamelCase` | `NodeType` | -| Functions, methods | `camelBack` | `sampleNeighbors` | -| Variables, parameters, members | `camelBack` | `numNodes` | -| Private/protected members | `camelBack` with `_` prefix | `_nodeFeatures` | -| Constants (`constexpr`, `const` globals, class constants) | `CamelCase` with `k` prefix | `kMaxBatchSize` | +| Identifier kind | Convention | Example | +| --------------------------------------------------------- | ---------------------------- | ----------------- | +| Classes, enums, unions | `PascalCase` | `DistDataset` | +| Type template parameters | `PascalCase` | `NodeType` | +| Functions, methods | `camelCase` | `sampleNeighbors` | +| Variables, parameters, members | `camelCase` | `numNodes` | +| Private/protected members | `camelCase` with `_` prefix | `_nodeFeatures` | +| Constants (`constexpr`, `const` globals, class constants) | `PascalCase` with `k` prefix | `kMaxBatchSize` | + +> **Note — clang-tidy option names:** `PascalCase` maps to clang-tidy's `CamelCase` enum value; `camelCase` maps to `camelBack`. ### Key option tuning diff --git a/docs/user_guide/getting_started/installation.md b/docs/user_guide/getting_started/installation.md index 4f3d40cdf..ef940db79 100644 --- a/docs/user_guide/getting_started/installation.md +++ b/docs/user_guide/getting_started/installation.md @@ -10,8 +10,10 @@ These are the current environments supported by GiGL ## Available Versions -You can see the available wheels for GiGL -[here](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl?project=external-snap-ci-github-gigl) +You can see the available wheels for GiGL: + +- [CPU wheels](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl?project=external-snap-ci-github-gigl) +- [CUDA wheels](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl-cu128?project=external-snap-ci-github-gigl) ## Install Prerequisites - setting up your dev machine @@ -107,7 +109,7 @@ Below we provide two ways to bootstrap an environment for using and/or developin ```bash pip install "gigl[pyg27-torch28-cu128, transform]==0.1.0" \ ---extra-index-url=https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl/simple/ \ +--extra-index-url=https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl-cu128/simple/ \ --extra-index-url=https://download.pytorch.org/whl/cu128 \ --extra-index-url=https://data.pyg.org/whl/torch-2.8.0+cu128.html ``` diff --git a/pyproject.toml b/pyproject.toml index 3d0591809..f365945e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -184,12 +184,26 @@ explicit = true format = "flat" # =============================== Google Artifact Registry Index ======================== +# Two separate indexes — one per torch variant — so pip always fetches the correct wheel. +# If both variants lived in the same index, pip would pick between them arbitrarily since +# both wheels share the same platform tag (linux_x86_64). Separate indexes remove the +# ambiguity and are essential once any extension contains CUDA kernels. +# +# The CPU registry reuses the original `gigl` repo for backwards compatibility. +# The CUDA registry is a new `gigl-cu128` repo that must be created in GCP project +# `external-snap-ci-github-gigl` before the release workflow will succeed. [[tool.uv.index]] -name = "gcp-release-registry" +name = "gcp-release-registry-cpu" url = "https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl/simple/" publish-url = "https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl" explicit = true +[[tool.uv.index]] +name = "gcp-release-registry-cu128" +url = "https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl-cu128/simple/" +publish-url = "https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl-cu128" +explicit = true + # ========== Mapping individual packages to their appropriate index ============= [tool.uv.sources] # ============= PyTorch hosted Package Index Mappings diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 92c6c633c..875d52647 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -24,7 +24,7 @@ _DIAGNOSTIC_RE = re.compile(r"^E\[[\d:.]+\] (\[.+\] .+)$") -def _check_file(source: Path) -> tuple[Path, list[str]]: +def _check_file(source: Path) -> list[str]: result = subprocess.run( [ "clangd-15", @@ -50,7 +50,7 @@ def _check_file(source: Path) -> tuple[Path, list[str]]: diagnostics = [ f"clangd exited with code {result.returncode} (tool error or crash)" ] - return source, diagnostics + return diagnostics def main() -> None: @@ -62,7 +62,8 @@ def main() -> None: with ThreadPoolExecutor(max_workers=min(os.cpu_count() or 1, 8)) as executor: futures = {executor.submit(_check_file, s): s for s in sources} for future in as_completed(futures): - source, diagnostics = future.result() + source = futures[future] + diagnostics = future.result() if diagnostics: failures[source] = diagnostics From a49a4c5808e3cd76f131f56f428ee64ea9d7dfc9 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 23 Apr 2026 00:34:20 +0000 Subject: [PATCH 080/148] Simplify requirements --- containers/Dockerfile.dataflow.src | 1 - containers/Dockerfile.src | 1 - pyproject.toml | 7 +++++-- requirements/install_py_deps.sh | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index da2be29dd..056158941 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -18,7 +18,6 @@ COPY deployment deployment COPY gigl gigl COPY snapchat snapchat COPY tests tests -RUN uv pip install "scikit-build-core>=0.10" "pybind11>=2.12" RUN uv pip install -e . WORKDIR / diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index 55b4eeee1..4125396b6 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -20,5 +20,4 @@ COPY snapchat snapchat COPY tests tests COPY examples examples -RUN uv pip install "scikit-build-core>=0.10" "pybind11>=2.12" RUN uv pip install -e . diff --git a/pyproject.toml b/pyproject.toml index f365945e9..a2e36b50b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,14 +106,17 @@ required-environments = [ no-build-isolation-package = ["gigl"] [dependency-groups] +cpp-build = [ + "scikit-build-core>=0.10", + "pybind11>=2.12", +] dev = [ + {include-group = "cpp-build"}, {include-group = "docs"}, {include-group = "lint"}, {include-group = "test"}, {include-group = "typing-stubs"}, "pre-commit==3.3.2", - "scikit-build-core>=0.10", - "pybind11>=2.12", ] docs = [ "astroid==3.3.11", # Newer versions of astroid are not compatible with sphinx==7.4.7 diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index 294b3dbec..a4f85ba51 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -146,7 +146,7 @@ install_gigl_lib_deps() { # https://docs.astral.sh/uv/reference/cli/#uv-sync uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} --no-install-project else - uv sync ${extra_deps_clause[@]} --locked ${flag_use_inexact_match} --no-install-project + uv sync ${extra_deps_clause[@]} --group cpp-build --locked ${flag_use_inexact_match} --no-install-project fi # Taken from https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script From 3738af6cca02750514278cb63c98c88d07c45f7b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 23 Apr 2026 00:49:32 +0000 Subject: [PATCH 081/148] Update uv --- uv.lock | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/uv.lock b/uv.lock index b5a61f573..435f2cd23 100644 --- a/uv.lock +++ b/uv.lock @@ -768,6 +768,10 @@ transform = [ ] [package.dev-dependencies] +cpp-build = [ + { name = "pybind11" }, + { name = "scikit-build-core" }, +] dev = [ { name = "astroid" }, { name = "mdformat" }, @@ -891,6 +895,10 @@ requires-dist = [ provides-extras = ["transform", "pyg27-torch28-cpu", "pyg27-torch28-cu128", "experimental"] [package.metadata.requires-dev] +cpp-build = [ + { name = "pybind11", specifier = ">=2.12" }, + { name = "scikit-build-core", specifier = ">=0.10" }, +] dev = [ { name = "astroid", specifier = "==3.3.11" }, { name = "mdformat", specifier = "==0.7.22" }, From 00d836f9714b664010a63d7683cebfbc6c8b02be Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 23 Apr 2026 00:59:05 +0000 Subject: [PATCH 082/148] [AUTOMATED] Update dep.vars, and other relevant files with new image names --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- gigl/dep_vars.env | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index ecdddd120..c93f1ad76 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 entrypoint: /bin/bash args: - -c diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index 7841701e1..ec535c24b 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:30e4e309ebff6ac167c09efa0ae70cc80b2c22c9.96.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 From 295138a1a2253e703d9a3a97d7bb52997b1201fe Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 23 Apr 2026 18:11:13 +0000 Subject: [PATCH 083/148] Update --- requirements/install_cpp_deps.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index cb3f2d815..3914e4d35 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -7,8 +7,6 @@ # Called by `make install_dev_deps` alongside install_py_deps.sh and # install_scala_deps.sh. # -# NOTE: On Linux, this script calls apt-get, which requires root privileges. -# Run as root or prefix with sudo. set -e set -x @@ -45,8 +43,8 @@ else # headers. Without this package clang++-15 cannot find standard headers like . # clang++-15 itself is needed because generate_compile_commands.py rewrites # compile_commands.json to use it so clangd natively understands the commands. - apt-get update -y - apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake + sudo apt-get update -y + sudo apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake # Verify cmake >= 3.18 (our CMakeLists.txt requires it; Ubuntu 20.04 apt provides 3.16). # sort -V (version sort) is a GNU extension only available on Linux — this block is From e07085404ef1c3c558d9c68a89a89c40ed36bfac Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 23 Apr 2026 19:01:03 +0000 Subject: [PATCH 084/148] Address comments --- .clang-format | 6 +-- CMakeLists.txt | 12 +----- Makefile | 3 +- docs/cpp_style_guide.md | 19 +-------- requirements/install_cpp_deps.sh | 64 +++++++++------------------- scripts/generate_compile_commands.py | 30 +++---------- scripts/run_cpp_lint.py | 3 +- 7 files changed, 35 insertions(+), 102 deletions(-) diff --git a/.clang-format b/.clang-format index d064de8a0..fccba9f02 100644 --- a/.clang-format +++ b/.clang-format @@ -39,12 +39,12 @@ ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] # Result: project-local headers (1) → torch/pybind11 (2) → system/third-party (3). # Add graphlearn_torch to the Priority 2 regex when GLT headers appear in the codebase. IncludeCategories: + - Regex: '.*' + Priority: 1 - Regex: '^<(torch|pybind11)/' Priority: 2 - - Regex: '^(<|"(gtest|isl|json)/)' + - Regex: '^(<|"gtest/)' Priority: 3 - - Regex: '.*' - Priority: 1 IncludeIsMainRegex: '^$' IndentCaseLabels: true IndentWidth: 4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0de039386..4aa7f0f0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,6 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) -endif() - # CMP0104: CMake 3.18+ warns when enable_language(CUDA) is called without # CMAKE_CUDA_ARCHITECTURES being set. Set it to OFF to tell CMake not to inject # any -gencode flags — Torch provides a comprehensive arch list via TORCH_LIBRARIES. @@ -88,15 +84,11 @@ find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_LIB_DIR}" REQUIRED set(GIGL_COMPILE_FLAGS - $<$:-O3> - $<$:-O0;-g> - -Wall -Wextra -Wno-unused-parameter + -O3 -g -Wall -Wextra -Wno-unused-parameter ) # nvcc does not accept bare -Wall/-Wextra; wrap them with -Xcompiler for CUDA sources. set(GIGL_COMPILE_FLAGS_CUDA - $<$:-O3> - $<$:-O0;-g> - -Xcompiler=-Wall,-Wextra,-Wno-unused-parameter + -O3 -Xcompiler=-g,-Wall,-Wextra,-Wno-unused-parameter ) # --------------------------------------------------------------------------- diff --git a/Makefile b/Makefile index 6e0b4c7e7..6f27bc423 100644 --- a/Makefile +++ b/Makefile @@ -99,9 +99,8 @@ unit_test_scala: clean_build_files_scala # Eventually, we should look into splitting these up. # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. -CMAKE_BUILD_TYPE ?= Release .cache/cpp_tests/.configured: CMakeLists.txt tests/unit/cpp/CMakeLists.txt - uv run cmake -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) + uv run cmake -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON touch .cache/cpp_tests/.configured unit_test_cpp: .cache/cpp_tests/.configured diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 434a67d4b..b8d2ea80e 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -26,22 +26,7 @@ ______________________________________________________________________ ## Build Configuration -The default build type is `Release` (`-O3`). To build with debug symbols (`-O0 -g`) — e.g. for stepping through -C++ code in a debugger — pass `Debug` explicitly: - -**Editable install (local development):** - -```bash -uv pip install -e . -C cmake.build-type=Debug -``` - -**C++ unit tests:** - -```bash -make unit_test_cpp CMAKE_BUILD_TYPE=Debug -``` - -To restore optimised builds, replace `Debug` with `Release`, or omit the flag (Release is the default). +All builds use `-O3 -g`: full optimization with debug symbols always enabled. Debug symbols add no runtime overhead and ensure stack traces are always readable. ______________________________________________________________________ @@ -103,7 +88,7 @@ Includes are sorted and split into three priority groups: | -------- | ---------------------------- | -------------------------------------------- | | 1 | `.*` | Local project headers (first) | | 2 | `^<(torch\|pybind11)/` | Torch and pybind11 headers | -| 3 | `^(<\|"(gtest\|isl\|json)/)` | System and other third-party headers (last) | +| 3 | `^(<\|"gtest/)` | System and other third-party headers (last) | > When GLT (`graphlearn_torch`) headers are added, include `graphlearn_torch` in the Priority 2 pattern. diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index 3914e4d35..d3e0a4353 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -7,56 +7,32 @@ # Called by `make install_dev_deps` alongside install_py_deps.sh and # install_scala_deps.sh. # +# NOTE: macOS is not supported. C++ tooling requires GLT, which does not run on macOS. set -e set -x -is_running_on_mac() { - [ "$(uname)" == "Darwin" ] -} - -if is_running_on_mac; then - # macOS ships its own Apple Clang via Xcode Command Line Tools. Homebrew - # intentionally does not put its llvm binaries on PATH to avoid shadowing - # Apple's clang. We therefore have to add the Homebrew llvm bin directory - # to PATH ourselves so that `clang-format-15` and `clang-tidy-15` resolve - # to the correct versions rather than being missing entirely. - brew install llvm@15 cmake - LLVM_BIN="$(brew --prefix llvm@15)/bin" - - # Append to any shell rc files that exist and don't already include it. - for rc_file in ~/.zshrc ~/.bashrc; do - if [ -f "$rc_file" ] && ! grep -qF "$LLVM_BIN" "$rc_file"; then - printf '\n# Added by GiGL install_cpp_deps.sh\nexport PATH="%s:$PATH"\n' "$LLVM_BIN" >> "$rc_file" - echo "NOTE: Added LLVM bin to PATH in $rc_file." - echo " Open a new terminal (or run: source $rc_file) to pick up the change." - fi - done +if [ "$(uname)" == "Darwin" ]; then + echo "ERROR: macOS is not supported for C++ tooling (GLT does not run on macOS)." >&2 + exit 1 +fi - export PATH="$LLVM_BIN:$PATH" -else - # On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly - # into /usr/bin. No PATH changes are needed since /usr/bin is already on PATH. - # Callers use the versioned names (clang-format-15, clang-tidy-15, clangd-15) - # directly so the version is explicit and greppable across the codebase. - # clang++-15 requires libstdc++-12-dev: on Ubuntu 22.04, clang++-15 looks for GCC 12 - # headers. Without this package clang++-15 cannot find standard headers like . - # clang++-15 itself is needed because generate_compile_commands.py rewrites - # compile_commands.json to use it so clangd natively understands the commands. - sudo apt-get update -y - sudo apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake +# On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly +# into /usr/bin. No PATH changes are needed since /usr/bin is already on PATH. +# Callers use the versioned names (clang-format-15, clang-tidy-15, clangd-15) +# directly so the version is explicit and greppable across the codebase. +# clang++-15 requires libstdc++-12-dev: on Ubuntu 22.04, clang++-15 looks for GCC 12 +# headers. Without this package clang++-15 cannot find standard headers like . +# clang++-15 itself is needed because generate_compile_commands.py rewrites +# compile_commands.json to use it so clangd natively understands the commands. +sudo apt-get update -y +sudo apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake - # Verify cmake >= 3.18 (our CMakeLists.txt requires it; Ubuntu 20.04 apt provides 3.16). - # sort -V (version sort) is a GNU extension only available on Linux — this block is - # intentionally inside the Linux branch; the macOS branch installs cmake via Homebrew - # which always provides a sufficiently recent version. - # sort -V -C exits 0 if the two lines are already in ascending version order - # (i.e. 3.18 <= cmake_version), non-zero otherwise. - cmake_version=$(cmake --version | awk 'NR==1{print $3}') - if ! printf '3.18\n%s\n' "$cmake_version" | sort -V -C 2>/dev/null; then - echo "ERROR: cmake >= 3.18 required, found $cmake_version. See https://cmake.org/download/" >&2 - exit 1 - fi +# Verify cmake >= 3.18 (our CMakeLists.txt requires it; Ubuntu 20.04 apt provides 3.16). +cmake_version=$(cmake --version | awk 'NR==1{print $3}') +if ! printf '3.18\n%s\n' "$cmake_version" | sort -V -C 2>/dev/null; then + echo "ERROR: cmake >= 3.18 required, found $cmake_version. See https://cmake.org/download/" >&2 + exit 1 fi echo "Finished installing C++ tooling" diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index 1d9462d25..ebbeb6790 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -3,10 +3,10 @@ Delegates to CMake (which already knows all include paths and compiler flags via find_package(Torch)) rather than manually constructing the database. -The build uses the system C++ compiler (g++) so that cmake, nvcc, and Torch's -cmake work without issues. After cmake writes compile_commands.json, the -compiler in each entry is replaced with ``clang++-15`` so that clangd natively -understands the commands without needing a ``--query-driver`` workaround. +CMake is configured with clang++-15 directly so clangd natively understands the +commands without needing a ``--query-driver`` workaround. This cmake invocation +is only for generating compile_commands.json — the actual extension build (via +``uv pip install -e .``) uses the system default compiler independently. Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and by ``make generate_compile_commands`` when you need to refresh the database @@ -17,11 +17,8 @@ make generate_compile_commands """ -import json -import shlex import subprocess from pathlib import Path -from typing import Any _REPO_ROOT: Path = Path(__file__).resolve().parent.parent _CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build_lint" @@ -38,6 +35,7 @@ def write_compile_commands() -> None: str(_REPO_ROOT), "-B", str(_CMAKE_BUILD_DIR), + "-DCMAKE_CXX_COMPILER=clang++-15", "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", ], capture_output=True, @@ -49,23 +47,7 @@ def write_compile_commands() -> None: ) raw_path = _CMAKE_BUILD_DIR / "compile_commands.json" - entries: list[dict[str, Any]] = json.loads(raw_path.read_text()) - - # Replace the compiler for .cpp entries with clang++-15 so clangd uses - # clang-native implicit include paths instead of guessing GCC's. - # Leave .cu entries unchanged so nvcc handles them correctly. - # The spec allows either "command" (string, Makefile generator) or - # "arguments" (array, Ninja generator); handle both. - for entry in entries: - if not entry.get("file", "").endswith(".cu"): - if "command" in entry: - tokens = shlex.split(entry["command"]) - tokens[0] = "clang++-15" - entry["command"] = shlex.join(tokens) - elif "arguments" in entry: - entry["arguments"][0] = "clang++-15" - - COMPILE_COMMANDS.write_text(json.dumps(entries, indent=2)) + COMPILE_COMMANDS.write_text(raw_path.read_text()) def main() -> None: diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 875d52647..6b501a1b6 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -10,7 +10,6 @@ uv run python scripts/run_cpp_lint.py [file2.cpp] ... """ -import os import re import subprocess import sys @@ -59,7 +58,7 @@ def main() -> None: sys.exit(0) failures: dict[Path, list[str]] = {} - with ThreadPoolExecutor(max_workers=min(os.cpu_count() or 1, 8)) as executor: + with ThreadPoolExecutor() as executor: futures = {executor.submit(_check_file, s): s for s in sources} for future in as_completed(futures): source = futures[future] From 5484c4237102e1356ccb892e9012a8a961154bf4 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 23 Apr 2026 22:33:03 +0000 Subject: [PATCH 085/148] Update --- docs/cpp_style_guide.md | 26 +++++++++++++------------- pyproject.toml | 12 ++++++++---- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index b8d2ea80e..d0d190411 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -15,18 +15,17 @@ make check_format_cpp # Check formatting without modifying (clang-format only, make check_lint_cpp # Run clang-tidy static analysis ``` -> **Note — CUDA files (`.cu`) are excluded from clang-tidy.** -> clang-tidy 15 does not support CUDA syntax and will error on `.cu` files. The Makefile -> defines `CPP_SOURCES_NO_CUDA` (which filters out `.cu` files) and passes only that set -> to clang-tidy. If you add a new `.cu` file, it will not appear in lint output — this is -> expected. Lint coverage for CUDA files requires upgrading to a clang-tidy version with -> CUDA support. +> **Note — CUDA files (`.cu`) are excluded from clang-tidy.** clang-tidy 15 does not support CUDA syntax and will error +> on `.cu` files. The Makefile defines `CPP_SOURCES_NO_CUDA` (which filters out `.cu` files) and passes only that set to +> clang-tidy. If you add a new `.cu` file, it will not appear in lint output — this is expected. Lint coverage for CUDA +> files requires upgrading to a clang-tidy version with CUDA support. ______________________________________________________________________ ## Build Configuration -All builds use `-O3 -g`: full optimization with debug symbols always enabled. Debug symbols add no runtime overhead and ensure stack traces are always readable. +All builds use `-O3 -g`: full optimization with debug symbols always enabled. Debug symbols add no runtime overhead and +ensure stack traces are always readable. ______________________________________________________________________ @@ -84,11 +83,11 @@ header. Includes are sorted and split into three priority groups: -| Priority | Pattern | Group | -| -------- | ---------------------------- | -------------------------------------------- | -| 1 | `.*` | Local project headers (first) | -| 2 | `^<(torch\|pybind11)/` | Torch and pybind11 headers | -| 3 | `^(<\|"gtest/)` | System and other third-party headers (last) | +| Priority | Pattern | Group | +| -------- | ---------------------- | ------------------------------------------- | +| 1 | `.*` | Local project headers (first) | +| 2 | `^<(torch\|pybind11)/` | Torch and pybind11 headers | +| 3 | `^(<\|"gtest/)` | System and other third-party headers (last) | > When GLT (`graphlearn_torch`) headers are added, include `graphlearn_torch` in the Priority 2 pattern. @@ -156,7 +155,8 @@ Enforced via `readability-identifier-naming`: | Private/protected members | `camelCase` with `_` prefix | `_nodeFeatures` | | Constants (`constexpr`, `const` globals, class constants) | `PascalCase` with `k` prefix | `kMaxBatchSize` | -> **Note — clang-tidy option names:** `PascalCase` maps to clang-tidy's `CamelCase` enum value; `camelCase` maps to `camelBack`. +> **Note — clang-tidy option names:** `PascalCase` maps to clang-tidy's `CamelCase` enum value; `camelCase` maps to +> `camelBack`. ### Key option tuning diff --git a/pyproject.toml b/pyproject.toml index a2e36b50b..2c993a16c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,10 +99,14 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", ] -# gigl's CMakeLists.txt requires torch headers at build time (find_package(Torch)). -# Disabling build isolation for gigl lets the build use whatever torch variant is -# already installed (CPU or CUDA), rather than downloading a fresh wheel into an -# isolated env that ignores the project's index routing. +# WANT: [tool.uv.extra-build-dependencies] +# WANT: gigl = [{ requirement = "torch", match-runtime = true }] +# +# BLOCKED: scikit-build-core passes -DPython_EXECUTABLE from sys.executable, +# which points at the runtime env's Python — not the isolated build env. +# CMake then discovers torch via that executable, bypassing uv's isolation. +# Until scikit-build-core or uv resolves this for cmake-based builds, +# we disable isolation so the declared config matches actual behavior. no-build-isolation-package = ["gigl"] [dependency-groups] From cf8a35b108e6a2bbdb94882146ed4304b58fec08 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 00:27:04 +0000 Subject: [PATCH 086/148] Potential fix --- CMakeLists.txt | 53 ++++++++++++++++++-------------------------------- Makefile | 3 ++- pyproject.toml | 9 --------- 3 files changed, 21 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aa7f0f0b..a459963db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,48 +39,33 @@ endif() find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) -# Locate pybind11's cmake config via the Python interpreter so this works -# whether pybind11 is installed system-wide or via pip. -execute_process( - COMMAND "${Python_EXECUTABLE}" -c - "import pybind11; print(pybind11.get_cmake_dir())" - OUTPUT_VARIABLE pybind11_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE _pybind11_result -) -if(NOT _pybind11_result EQUAL 0) - message(FATAL_ERROR "Failed to locate pybind11. Run: make install_dev_deps") -endif() -find_package(pybind11 CONFIG REQUIRED) +# Locate pybind11 and torch cmake configs by scanning CMAKE_PREFIX_PATH, which +# both scikit-build-core and the Makefile set to the active environment's +# site-packages directory. +foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) + if(NOT pybind11_DIR AND EXISTS "${_prefix}/pybind11/share/cmake/pybind11") + set(pybind11_DIR "${_prefix}/pybind11/share/cmake/pybind11") + endif() + if(NOT TORCH_CMAKE_PREFIX AND EXISTS "${_prefix}/torch/share/cmake") + set(TORCH_CMAKE_PREFIX "${_prefix}/torch/share/cmake") + endif() +endforeach() -# Locate PyTorch headers via its own cmake prefix path (works for both CPU and CUDA torch). -execute_process( - COMMAND "${Python_EXECUTABLE}" -c - "import torch; print(torch.utils.cmake_prefix_path)" - OUTPUT_VARIABLE TORCH_CMAKE_PREFIX - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE _torch_result -) -if(NOT _torch_result EQUAL 0) - message(FATAL_ERROR "Failed to locate torch. Run: make install_dev_deps") +if(NOT pybind11_DIR) + message(FATAL_ERROR "Cannot find pybind11 cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") +endif() +if(NOT TORCH_CMAKE_PREFIX) + message(FATAL_ERROR "Cannot find torch cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") endif() +find_package(pybind11 CONFIG REQUIRED) find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") # torch_python provides the pybind11 type casters for at::Tensor. It is not # included in TORCH_LIBRARIES but is required for extensions that pass tensors # across the Python/C++ boundary. -execute_process( - COMMAND "${Python_EXECUTABLE}" -c - "import torch, os; print(os.path.join(os.path.dirname(torch.__file__), 'lib'))" - OUTPUT_VARIABLE TORCH_LIB_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE _torch_lib_result -) -if(NOT _torch_lib_result EQUAL 0) - message(FATAL_ERROR "Failed to locate torch lib dir. Run: make install_dev_deps") -endif() -find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_LIB_DIR}" REQUIRED) +# TORCH_INSTALL_PREFIX is set to /torch by TorchConfig.cmake. +find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_INSTALL_PREFIX}/lib" REQUIRED) set(GIGL_COMPILE_FLAGS diff --git a/Makefile b/Makefile index 6f27bc423..a63b080a9 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,8 @@ unit_test_scala: clean_build_files_scala # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. .cache/cpp_tests/.configured: CMakeLists.txt tests/unit/cpp/CMakeLists.txt - uv run cmake -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON + uv run cmake -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON \ + "-DCMAKE_PREFIX_PATH=$$(uv run python -c 'import site; print(site.getsitepackages()[0])')" touch .cache/cpp_tests/.configured unit_test_cpp: .cache/cpp_tests/.configured diff --git a/pyproject.toml b/pyproject.toml index 2c993a16c..18864be7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,15 +99,6 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", ] -# WANT: [tool.uv.extra-build-dependencies] -# WANT: gigl = [{ requirement = "torch", match-runtime = true }] -# -# BLOCKED: scikit-build-core passes -DPython_EXECUTABLE from sys.executable, -# which points at the runtime env's Python — not the isolated build env. -# CMake then discovers torch via that executable, bypassing uv's isolation. -# Until scikit-build-core or uv resolves this for cmake-based builds, -# we disable isolation so the declared config matches actual behavior. -no-build-isolation-package = ["gigl"] [dependency-groups] cpp-build = [ From abcb704149849e5ecc1260744a77faff1ae8a61b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 00:52:22 +0000 Subject: [PATCH 087/148] Fix --- gigl/distributed/dist_sampling_producer.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/gigl/distributed/dist_sampling_producer.py b/gigl/distributed/dist_sampling_producer.py index 8a43f90f4..9c4624da8 100644 --- a/gigl/distributed/dist_sampling_producer.py +++ b/gigl/distributed/dist_sampling_producer.py @@ -105,28 +105,6 @@ def _sampling_worker_loop( current_device=current_device, ) - if isinstance(sampler_options, KHopNeighborSamplerOptions): - dist_sampler = DistNeighborSampler( - *shared_sampler_args, - seed=sampling_config.seed, - ) - elif isinstance(sampler_options, PPRSamplerOptions): - assert degree_tensors is not None - dist_sampler = DistPPRNeighborSampler( - *shared_sampler_args, - seed=sampling_config.seed, - alpha=sampler_options.alpha, - eps=sampler_options.eps, - max_ppr_nodes=sampler_options.max_ppr_nodes, - num_neighbors_per_hop=sampler_options.num_neighbors_per_hop, - total_degree_dtype=sampler_options.total_degree_dtype, - degree_tensors=degree_tensors, - max_fetch_iterations=sampler_options.max_fetch_iterations, - ) - else: - raise NotImplementedError( - f"Unsupported sampler options type: {type(sampler_options)}" - ) dist_sampler.start_loop() unshuffled_index_loader: Optional[DataLoader] From 928d5c755d5c9be12d3dc2dac3af12f4a623558f Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 01:12:24 +0000 Subject: [PATCH 088/148] Update --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a63b080a9..a7a61405d 100644 --- a/Makefile +++ b/Makefile @@ -99,9 +99,9 @@ unit_test_scala: clean_build_files_scala # Eventually, we should look into splitting these up. # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. -.cache/cpp_tests/.configured: CMakeLists.txt tests/unit/cpp/CMakeLists.txt - uv run cmake -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON \ - "-DCMAKE_PREFIX_PATH=$$(uv run python -c 'import site; print(site.getsitepackages()[0])')" +.cache/cpp_tests/.configured: CMakeLists.txt tests/unit/cpp/CMakeLists.txt .cache/cmake_build/CMakeInit.txt + uv run cmake -C .cache/cmake_build/CMakeInit.txt \ + -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON touch .cache/cpp_tests/.configured unit_test_cpp: .cache/cpp_tests/.configured From 1de76f7f413aa865c4ed2716b0742689bf1c0fdc Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 21:41:30 +0000 Subject: [PATCH 089/148] Update --- .../csrc/sampling/ppr_forward_push.cpp | 0 .../csrc/sampling/ppr_forward_push.h | 0 .../csrc/sampling/python_ppr_forward_push.cpp | 0 gigl/csrc/sampling/__init__.py | 10 +-------- gigl/csrc/sampling/ppr_forward_push.pyi | 22 ------------------- 5 files changed, 1 insertion(+), 31 deletions(-) rename {gigl => gigl-core}/csrc/sampling/ppr_forward_push.cpp (100%) rename {gigl => gigl-core}/csrc/sampling/ppr_forward_push.h (100%) rename {gigl => gigl-core}/csrc/sampling/python_ppr_forward_push.cpp (100%) delete mode 100644 gigl/csrc/sampling/ppr_forward_push.pyi diff --git a/gigl/csrc/sampling/ppr_forward_push.cpp b/gigl-core/csrc/sampling/ppr_forward_push.cpp similarity index 100% rename from gigl/csrc/sampling/ppr_forward_push.cpp rename to gigl-core/csrc/sampling/ppr_forward_push.cpp diff --git a/gigl/csrc/sampling/ppr_forward_push.h b/gigl-core/csrc/sampling/ppr_forward_push.h similarity index 100% rename from gigl/csrc/sampling/ppr_forward_push.h rename to gigl-core/csrc/sampling/ppr_forward_push.h diff --git a/gigl/csrc/sampling/python_ppr_forward_push.cpp b/gigl-core/csrc/sampling/python_ppr_forward_push.cpp similarity index 100% rename from gigl/csrc/sampling/python_ppr_forward_push.cpp rename to gigl-core/csrc/sampling/python_ppr_forward_push.cpp diff --git a/gigl/csrc/sampling/__init__.py b/gigl/csrc/sampling/__init__.py index 5c8b47393..5e307b635 100644 --- a/gigl/csrc/sampling/__init__.py +++ b/gigl/csrc/sampling/__init__.py @@ -1,11 +1,3 @@ -try: - from gigl.csrc.sampling.ppr_forward_push import PPRForwardPushState -except ImportError as e: - raise ImportError( - f"Failed to import PPR C++ extension: {e}. " - "If the extension is not yet compiled, run `make build_cpp_extensions` from the GiGL root. " - "If it is compiled, ensure `import torch` is called before importing this module " - "so that libtorch shared libraries are loaded into the process first." - ) from e +from gigl_core import PPRForwardPushState __all__ = ["PPRForwardPushState"] diff --git a/gigl/csrc/sampling/ppr_forward_push.pyi b/gigl/csrc/sampling/ppr_forward_push.pyi deleted file mode 100644 index 9a3c78fea..000000000 --- a/gigl/csrc/sampling/ppr_forward_push.pyi +++ /dev/null @@ -1,22 +0,0 @@ -import torch - -class PPRForwardPushState: - def __init__( - self, - seed_nodes: torch.Tensor, - seed_node_type_id: int, - alpha: float, - requeue_threshold_factor: float, - node_type_to_edge_type_ids: list[list[int]], - edge_type_to_dst_ntype_id: list[int], - degree_tensors: list[torch.Tensor], - ) -> None: ... - def drain_queue(self) -> dict[int, torch.Tensor] | None: ... - def push_residuals( - self, - fetched_by_etype_id: dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]], - ) -> None: ... - def extract_top_k( - self, max_ppr_nodes: int - ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: ... - def get_nodes_drained_per_iteration(self) -> list[int]: ... From d4b7da3d7a92168c32ed19fc824291cf4ba9eba0 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 21:41:58 +0000 Subject: [PATCH 090/148] Update to gigl-core --- MANIFEST.in | 1 - Makefile | 25 +- containers/Dockerfile.src | 13 +- gigl-core/CMakeLists.txt | 84 + gigl-core/README.md | 12 + gigl-core/pyproject.toml | 37 + gigl-core/src/gigl_core/__init__.py | 11 + gigl-core/src/gigl_core/ppr_forward_push.pyi | 22 + gigl-core/src/gigl_core/py.typed | 0 gigl-core/tests/CMakeLists.txt | 52 + gigl-core/tests/infrastructure_test.cpp | 12 + pyproject.toml | 41 +- requirements/install_py_deps.sh | 12 +- scripts/generate_compile_commands.py | 25 +- uv.lock | 4781 ------------------ 15 files changed, 303 insertions(+), 4825 deletions(-) create mode 100644 gigl-core/CMakeLists.txt create mode 100644 gigl-core/README.md create mode 100644 gigl-core/pyproject.toml create mode 100644 gigl-core/src/gigl_core/__init__.py create mode 100644 gigl-core/src/gigl_core/ppr_forward_push.pyi create mode 100644 gigl-core/src/gigl_core/py.typed create mode 100644 gigl-core/tests/CMakeLists.txt create mode 100644 gigl-core/tests/infrastructure_test.cpp delete mode 100644 uv.lock diff --git a/MANIFEST.in b/MANIFEST.in index b53f4d2cc..ec343c7d5 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,2 @@ global-exclude tests/* recursive-include gigl/deps *.jar -recursive-include gigl/csrc *.cpp *.cu *.h *.cuh diff --git a/Makefile b/Makefile index a7a61405d..60508fba7 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG?=${DOCKER_IMAGE_MAIN_CPU_NAME}:${DATE} DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${DATE} PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts -CPP_SOURCES:=$(shell find gigl/csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) +CPP_SOURCES:=$(shell find gigl-core/csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) # clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). # Exclude .cu files from tidy targets; clang-format and clangd handle them fine. CPP_SOURCES_NO_CUDA:=$(filter-out %.cu,$(CPP_SOURCES)) @@ -99,9 +99,9 @@ unit_test_scala: clean_build_files_scala # Eventually, we should look into splitting these up. # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. -.cache/cpp_tests/.configured: CMakeLists.txt tests/unit/cpp/CMakeLists.txt .cache/cmake_build/CMakeInit.txt - uv run cmake -C .cache/cmake_build/CMakeInit.txt \ - -S . -B .cache/cpp_tests -DGIGL_BUILD_TESTS=ON +.cache/cpp_tests/.configured: gigl-core/CMakeLists.txt gigl-core/tests/CMakeLists.txt gigl-core/.cache/cmake_build/CMakeInit.txt + uv run cmake -C gigl-core/.cache/cmake_build/CMakeInit.txt \ + -S gigl-core -B .cache/cpp_tests -DGIGL_CORE_BUILD_TESTS=ON touch .cache/cpp_tests/.configured unit_test_cpp: .cache/cpp_tests/.configured @@ -172,18 +172,17 @@ format: format_py format_cpp format_scala format_md type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs -# Stamp-file guard: uv pip install -e . triggers a full CMake configure-and-build +# Stamp-file guard: uv pip install -e gigl-core/ triggers a full CMake configure-and-build # cycle (loading torch headers) even when nothing changed. By making the stamp file -# depend on C++ sources, CMakeLists.txt, and pyproject.toml, make skips the reinstall +# depend on C++ sources and gigl-core/pyproject.toml, make skips the reinstall # on subsequent runs unless something actually changed. The stamp file lives inside -# .cache/cmake_build so it is automatically invalidated if the build dir is cleaned. -.cache/cmake_build/.gigl_built: $(shell find gigl/csrc \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) CMakeLists.txt pyproject.toml - uv pip install -e . - touch .cache/cmake_build/.gigl_built +# gigl-core/.cache/cmake_build so it is automatically invalidated if the build dir is cleaned. +gigl-core/.cache/cmake_build/CMakeInit.txt: $(shell find gigl-core/csrc \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) gigl-core/CMakeLists.txt gigl-core/pyproject.toml + uv pip install -e gigl-core/ -build_cpp_extensions: .cache/cmake_build/.gigl_built +build_cpp_extensions: gigl-core/.cache/cmake_build/CMakeInit.txt -generate_compile_commands: +generate_compile_commands: gigl-core/.cache/cmake_build/CMakeInit.txt uv run python -m scripts.generate_compile_commands check_lint_cpp: generate_compile_commands @@ -202,7 +201,7 @@ lint_test: check_format assert_yaml_configs_parse check_lint_cpp # Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent # after switching between branches with substantially different CMakeLists.txt structure. clean_cpp: - rm -rf .cache/cpp_tests .cache/cmake_build .cache/cmake_build_lint + rm -rf .cache/cpp_tests .cache/cmake_build_lint gigl-core/.cache/cmake_build # compiles current working state of scala projects to local jars compile_jars: diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index 4125396b6..c43de4c9a 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -5,11 +5,6 @@ FROM $BASE_IMAGE # See https://beam.apache.org/documentation/sdks/python-pipxeline-dependencies/#create-reproducible-environments. WORKDIR /gigl -# scikit-build-core needs CMakeLists.txt (build definition), MANIFEST.in (sdist source list), -# and README.md (required by pyproject.toml's readme field) before `uv pip install -e .` -# triggers the CMake build. Without these, the install will error at configure time. -COPY CMakeLists.txt CMakeLists.txt -COPY MANIFEST.in MANIFEST.in COPY README.md README.md COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock @@ -20,4 +15,10 @@ COPY snapchat snapchat COPY tests tests COPY examples examples -RUN uv pip install -e . +# Install gigl (pure Python — fast, no CMake). +RUN uv pip install . + +# Build and install gigl-core C++ extensions. gigl-core/ must be present +# for scikit-build-core to run CMake and link against torch. +COPY gigl-core gigl-core +RUN uv pip install gigl-core/ diff --git a/gigl-core/CMakeLists.txt b/gigl-core/CMakeLists.txt new file mode 100644 index 000000000..83420f2b0 --- /dev/null +++ b/gigl-core/CMakeLists.txt @@ -0,0 +1,84 @@ +cmake_minimum_required(VERSION 3.18) +project(gigl_core CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# CMP0104: CMake 3.18+ warns when enable_language(CUDA) is called without +# CMAKE_CUDA_ARCHITECTURES being set. Set it to OFF — Torch provides a +# comprehensive arch list via TORCH_LIBRARIES. +cmake_policy(SET CMP0104 NEW) +set(CMAKE_CUDA_ARCHITECTURES OFF) + +# Enable CUDA only when the toolkit is present; allows the same CMakeLists.txt +# to build on CPU-only machines without requiring nvcc. find_package(Torch) +# internally calls enable_language(CUDA) when torch was built with CUDA support, +# which requires CMAKE_CUDA_COMPILER to be set — hence the nvcc hint below. +include(CheckLanguage) +check_language(CUDA) +if(NOT CMAKE_CUDA_COMPILER) + find_program(CMAKE_CUDA_COMPILER nvcc HINTS /usr/local/cuda/bin) +endif() +if(CMAKE_CUDA_COMPILER) + enable_language(CUDA) + set(CMAKE_CUDA_STANDARD 17) + set(CMAKE_CUDA_STANDARD_REQUIRED ON) +endif() + +find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) + +# Locate pybind11 and torch cmake configs by scanning CMAKE_PREFIX_PATH, which +# scikit-build-core sets to the active environment's site-packages directory. +foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) + if(NOT pybind11_DIR AND EXISTS "${_prefix}/pybind11/share/cmake/pybind11") + set(pybind11_DIR "${_prefix}/pybind11/share/cmake/pybind11") + endif() + if(NOT TORCH_CMAKE_PREFIX AND EXISTS "${_prefix}/torch/share/cmake") + set(TORCH_CMAKE_PREFIX "${_prefix}/torch/share/cmake") + endif() +endforeach() + +if(NOT pybind11_DIR) + message(FATAL_ERROR "Cannot find pybind11 cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") +endif() +if(NOT TORCH_CMAKE_PREFIX) + message(FATAL_ERROR "Cannot find torch cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") +endif() + +find_package(pybind11 CONFIG REQUIRED) +find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") + +# torch_python provides the pybind11 type casters for at::Tensor. It is not +# included in TORCH_LIBRARIES but is required for extensions that pass tensors +# across the Python/C++ boundary. +find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_INSTALL_PREFIX}/lib" REQUIRED) + +set(GIGL_COMPILE_FLAGS -O3 -g -Wall -Wextra -Wno-unused-parameter) +# nvcc does not accept bare -Wall/-Wextra; wrap with -Xcompiler for CUDA sources. +set(GIGL_COMPILE_FLAGS_CUDA -O3 -Xcompiler=-g,-Wall,-Wextra,-Wno-unused-parameter) + +# --------------------------------------------------------------------------- +# ppr_forward_push extension module +# --------------------------------------------------------------------------- +pybind11_add_module(ppr_forward_push + csrc/sampling/python_ppr_forward_push.cpp + csrc/sampling/ppr_forward_push.cpp +) +target_link_libraries(ppr_forward_push PRIVATE "${TORCH_LIBRARIES}" "${TORCH_PYTHON_LIBRARY}") +target_compile_options(ppr_forward_push PRIVATE + $<$:${GIGL_COMPILE_FLAGS}> + $<$:${GIGL_COMPILE_FLAGS_CUDA}> +) +# TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. +# PyTorch's own build system sets this; we must define it explicitly here. +target_compile_definitions(ppr_forward_push PRIVATE TORCH_EXTENSION_NAME=ppr_forward_push) +# Install into the gigl_core/ subdirectory so the .so is importable as +# gigl_core.ppr_forward_push after editable install. +install(TARGETS ppr_forward_push DESTINATION gigl_core) + +option(GIGL_CORE_BUILD_TESTS "Build C++ unit tests (used by make unit_test_cpp)" OFF) +if(GIGL_CORE_BUILD_TESTS) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/gigl-core/README.md b/gigl-core/README.md new file mode 100644 index 000000000..7ff32c88e --- /dev/null +++ b/gigl-core/README.md @@ -0,0 +1,12 @@ +# gigl-core + +C++/CUDA pybind11 extension modules for [GiGL](https://github.com/snapchat/gigl). + +This package contains the compiled native extensions. It is a workspace member of the +main `gigl` package and is built separately via scikit-build-core. + +## Building + +```bash +uv pip install -e gigl-core/ +``` diff --git a/gigl-core/pyproject.toml b/gigl-core/pyproject.toml new file mode 100644 index 000000000..2a63687df --- /dev/null +++ b/gigl-core/pyproject.toml @@ -0,0 +1,37 @@ +[project] +name = "gigl-core" +description = "GiGL C++/CUDA kernels (pybind11 extensions)" +readme = "README.md" +version = "0.2.0" +requires-python = "==3.11.*" +# Torch is resolved from the ambient environment. gigl-core wheels are ABI-bound +# to the torch variant they were built against (cpu or cu128). The parent `gigl` +# extras (pyg27-torch28-cpu / pyg27-torch28-cu128) already pin torch==2.8, and +# pip picks the matching gigl-core wheel from whichever GCP registry the user +# configured for installing gigl itself. +dependencies = [] + +[build-system] +requires = ["scikit-build-core>=0.10", "pybind11>=2.12"] +build-backend = "scikit_build_core.build" + +[tool.scikit-build] +cmake.version = ">=3.18" +build-dir = ".cache/cmake_build" +# Default editable mode is `redirect`: scikit-build-core writes the compiled .so +# into .cache/cmake_build/ and installs an import-hook shim into site-packages +# that resolves gigl_core.ppr_forward_push to that path. `editable.rebuild` +# stays off so imports never block on CMake — explicit `uv pip install -e gigl-core/` +# drives rebuilds. +editable.rebuild = false + +[tool.uv] +# Invalidate the uv build cache when any of these inputs change. +cache-keys = [ + { file = "pyproject.toml" }, + { file = "CMakeLists.txt" }, + { file = "csrc/**/*.h" }, + { file = "csrc/**/*.cpp" }, + { file = "csrc/**/*.cu" }, + { file = "csrc/**/*.cuh" }, +] diff --git a/gigl-core/src/gigl_core/__init__.py b/gigl-core/src/gigl_core/__init__.py new file mode 100644 index 000000000..7bf8c9987 --- /dev/null +++ b/gigl-core/src/gigl_core/__init__.py @@ -0,0 +1,11 @@ +try: + from gigl_core.ppr_forward_push import PPRForwardPushState +except ImportError as e: + raise ImportError( + f"Failed to import PPR C++ extension: {e}. " + "If the extension is not yet compiled, run `uv pip install -e gigl-core/` from the GiGL root. " + "If it is compiled, ensure `import torch` is called before importing this module " + "so that libtorch shared libraries are loaded into the process first." + ) from e + +__all__ = ["PPRForwardPushState"] diff --git a/gigl-core/src/gigl_core/ppr_forward_push.pyi b/gigl-core/src/gigl_core/ppr_forward_push.pyi new file mode 100644 index 000000000..9a3c78fea --- /dev/null +++ b/gigl-core/src/gigl_core/ppr_forward_push.pyi @@ -0,0 +1,22 @@ +import torch + +class PPRForwardPushState: + def __init__( + self, + seed_nodes: torch.Tensor, + seed_node_type_id: int, + alpha: float, + requeue_threshold_factor: float, + node_type_to_edge_type_ids: list[list[int]], + edge_type_to_dst_ntype_id: list[int], + degree_tensors: list[torch.Tensor], + ) -> None: ... + def drain_queue(self) -> dict[int, torch.Tensor] | None: ... + def push_residuals( + self, + fetched_by_etype_id: dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]], + ) -> None: ... + def extract_top_k( + self, max_ppr_nodes: int + ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: ... + def get_nodes_drained_per_iteration(self) -> list[int]: ... diff --git a/gigl-core/src/gigl_core/py.typed b/gigl-core/src/gigl_core/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/gigl-core/tests/CMakeLists.txt b/gigl-core/tests/CMakeLists.txt new file mode 100644 index 000000000..10b9520cf --- /dev/null +++ b/gigl-core/tests/CMakeLists.txt @@ -0,0 +1,52 @@ +include(CheckLanguage) +check_language(CUDA) +if(CMAKE_CUDA_COMPILER) + enable_language(CUDA) + set(CMAKE_CUDA_STANDARD 17) + set(CMAKE_CUDA_STANDARD_REQUIRED ON) +endif() + +# --------------------------------------------------------------------------- +# GoogleTest via FetchContent +# --------------------------------------------------------------------------- +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.14.0 + GIT_SHALLOW TRUE +) +# Prevent GoogleTest from overriding the compiler's runtime on Windows +# (no-op on Linux/Mac, but required for portable CMake config). +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +# Required for add_test() to register tests with CTest. +enable_testing() + +# --------------------------------------------------------------------------- +# Auto-discover test targets +# --------------------------------------------------------------------------- +# Any file named *_test.cpp in this directory (or subdirectories) is +# automatically compiled into its own test binary and registered with CTest. +# To add a new test suite, drop a *_test.cpp file here — no changes to this +# file required. This matches the *_test.py convention used for Python tests. +if(CMAKE_CUDA_COMPILER) + file(GLOB_RECURSE TEST_SOURCES "*_test.cpp" "*_test.cu") +else() + file(GLOB_RECURSE TEST_SOURCES "*_test.cpp") +endif() + +foreach(test_source ${TEST_SOURCES}) + # Derive a unique binary name from the path relative to this directory, e.g.: + # ppr_forward_push_test.cpp → ppr_forward_push_test + # sampling/ppr_forward_push_test.cpp → sampling_ppr_forward_push_test + file(RELATIVE_PATH _rel "${CMAKE_CURRENT_SOURCE_DIR}" "${test_source}") + string(REPLACE "/" "_" test_name "${_rel}") + string(REGEX REPLACE "\\.[^.]+$" "" test_name "${test_name}") + add_executable(${test_name} ${test_source}) + target_link_libraries(${test_name} GTest::gtest_main) + # add_test registers the binary with CTest. Each *_test binary is one + # CTest entry; GoogleTest itself reports individual TEST() results inside it. + add_test(NAME ${test_name} COMMAND ${test_name}) +endforeach() diff --git a/gigl-core/tests/infrastructure_test.cpp b/gigl-core/tests/infrastructure_test.cpp new file mode 100644 index 000000000..eb3c1aa3d --- /dev/null +++ b/gigl-core/tests/infrastructure_test.cpp @@ -0,0 +1,12 @@ +// Placeholder C++ unit test. +// +// This file exists to verify that the GoogleTest infrastructure compiles and +// runs end-to-end. + +#include + +// A trivial sanity-check test — if this fails, something is very wrong with +// the build environment itself. +TEST(PlaceholderTest, BasicArithmetic) { + EXPECT_EQ(1 + 1, 2); +} diff --git a/pyproject.toml b/pyproject.toml index 18864be7c..1c9c49398 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,9 @@ requires-python = "==3.11.*" # Limited by tfx-bsl not having wheels available fo dependencies = [ "argo-workflows", "chardet", + # gigl-core hosts all C++ / CUDA / pybind11 extensions. Separate wheel per torch + # variant (cpu/cu128). Same pattern PyG uses for pyg_lib. + "gigl-core", "google-cloud-aiplatform", "google-cloud-dataproc", "google-cloud-logging", @@ -99,6 +102,10 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", ] +# gigl-core uses torch from the ambient environment (no isolated build env). +# This matches how PyG's pyg_lib is built — torch is never on PyPI so build +# isolation would prevent finding it. +no-build-isolation-package = ["gigl-core"] [dependency-groups] cpp-build = [ @@ -240,27 +247,29 @@ torch_spline_conv = [ { extra = "pyg27-torch28-cpu", index = "pyg-torch28-cpu" }, { extra = "pyg27-torch28-cu128", index = "pyg-torch28-cu128" }, ] - +# gigl-core is auto-discovered as a local package — uv sync / uv pip install -e gigl-core/ +# builds it from source via scikit-build-core. At release install time, published gigl +# and gigl-core wheels are resolved from the same GCP registry. +gigl-core = { workspace = true } # ===================== Build/Project Configurations =========================== -# gigl releases two wheels (pyg27-torch28-cpu and pyg27-torch28-cu128), one -# built against CPU torch headers and one against CUDA torch headers. See -# release.yml for the build matrix. CMakeLists.txt auto-discovers python_*.cu -# files alongside python_*.cpp, so CUDA kernels can be added without changes -# to the build configuration. +# gigl is a pure-Python package. All C++/CUDA kernels live in the gigl-core +# wheel (see gigl-core/pyproject.toml). Release builds two variants per package: +# cpu and cu128. gigl's build stays fast because no CMake runs here. [build-system] -requires = [ - "scikit-build-core>=0.10", - "pybind11>=2.12", -] -build-backend = "scikit_build_core.build" +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +include = ["gigl*", "snapchat*"] +exclude = ["gigl-core*", "tests*"] +namespaces = true -[tool.scikit-build] -cmake.version = ">=3.18" -build-dir = ".cache/cmake_build" -wheel.packages = ["gigl", "snapchat"] -editable.mode = "redirect" +[tool.setuptools.package-data] +# Include dep_vars.env from the root directory +"gigl" = ["dep_vars.env", "**/*.yaml"] +"gigl.scripts" = ["*.sh"] [project.urls] Homepage = "https://github.com/snapchat/gigl" diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index a4f85ba51..1cd491b98 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -136,11 +136,13 @@ install_gigl_lib_deps() { flag_use_inexact_match="--inexact" fi - # --no-install-project: skip building and installing the gigl package itself here. - # The project is installed separately via `uv pip install -e .` - # (see Makefile install_dev_deps/install_deps targets and the *.src Dockerfiles). - # This avoids scikit-build-core requiring all source files (e.g. README.md, CMakeLists.txt) - # to be present in environments that only need the dependencies (e.g. base Docker images). + # --no-install-project: skip building and installing the workspace members (gigl, + # gigl-core) here. They are installed separately: + # - gigl (pure Python): `uv pip install .` in *.src Dockerfiles + # - gigl-core (C++ extension): `uv pip install gigl-core/` in *.src Dockerfiles + # Base Docker images only copy pyproject.toml + uv.lock, not gigl-core/. Without + # this flag, uv sync would try to build gigl-core's C++ extension and fail because + # the source tree is absent. if [[ $DEV -eq 1 ]] then # https://docs.astral.sh/uv/reference/cli/#uv-sync diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py index ebbeb6790..4500da3dd 100644 --- a/scripts/generate_compile_commands.py +++ b/scripts/generate_compile_commands.py @@ -6,7 +6,7 @@ CMake is configured with clang++-15 directly so clangd natively understands the commands without needing a ``--query-driver`` workaround. This cmake invocation is only for generating compile_commands.json — the actual extension build (via -``uv pip install -e .``) uses the system default compiler independently. +``uv pip install -e gigl-core/``) uses the system default compiler independently. Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and by ``make generate_compile_commands`` when you need to refresh the database @@ -21,18 +21,37 @@ from pathlib import Path _REPO_ROOT: Path = Path(__file__).resolve().parent.parent +_GIGL_CORE_DIR: Path = _REPO_ROOT / "gigl-core" +# CMakeInit.txt is generated by scikit-build-core during `uv pip install -e gigl-core/`. +# It sets CMAKE_PREFIX_PATH to the environment's site-packages so CMake can find +# pybind11 and torch. Must exist before this script is called (run build_cpp_extensions). +_GIGL_CORE_CMAKE_INIT: Path = ( + _GIGL_CORE_DIR / ".cache" / "cmake_build" / "CMakeInit.txt" +) _CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build_lint" COMPILE_COMMANDS: Path = _REPO_ROOT / ".cache" / "compile_commands.json" def write_compile_commands() -> None: - """Run CMake to generate .cache/compile_commands.json.""" + """Run CMake to generate .cache/compile_commands.json. + + Configures gigl-core's CMakeLists.txt with clang++-15, loading + ``gigl-core/.cache/cmake_build/CMakeInit.txt`` (written by + ``uv pip install -e gigl-core/``) for the correct ``CMAKE_PREFIX_PATH``. + """ + if not _GIGL_CORE_CMAKE_INIT.exists(): + raise FileNotFoundError( + f"{_GIGL_CORE_CMAKE_INIT} not found. " + "Run `make build_cpp_extensions` first to generate it." + ) _CMAKE_BUILD_DIR.mkdir(parents=True, exist_ok=True) result = subprocess.run( [ "cmake", + "-C", + str(_GIGL_CORE_CMAKE_INIT), "-S", - str(_REPO_ROOT), + str(_GIGL_CORE_DIR), "-B", str(_CMAKE_BUILD_DIR), "-DCMAKE_CXX_COMPILER=clang++-15", diff --git a/uv.lock b/uv.lock deleted file mode 100644 index 435f2cd23..000000000 --- a/uv.lock +++ /dev/null @@ -1,4781 +0,0 @@ -version = 1 -revision = 3 -requires-python = "==3.11.*" -resolution-markers = [ - "extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'", - "sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", - "platform_machine != 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", - "platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", - "extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", -] -required-markers = [ - "platform_machine == 'x86_64' and sys_platform == 'linux'", - "platform_machine == 'arm64' and sys_platform == 'darwin'", -] -conflicts = [[ - { package = "gigl", extra = "pyg27-torch28-cpu" }, - { package = "gigl", extra = "pyg27-torch28-cu128" }, -]] - -[[package]] -name = "absl-py" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/c9/45ecff8055b0ce2ad2bfbf1f438b5b8605873704d50610eda05771b865a0/absl-py-1.4.0.tar.gz", hash = "sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d", size = 112028, upload-time = "2023-01-11T18:05:46.544Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/87/de5c32fa1b1c6c3305d576e299801d8655c175ca9557019906247b994331/absl_py-1.4.0-py3-none-any.whl", hash = "sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47", size = 126549, upload-time = "2023-01-11T18:05:44.967Z" }, -] - -[[package]] -name = "accessible-pygments" -version = "0.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, -] - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.13.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994, upload-time = "2025-10-28T20:59:39.937Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/74/b321e7d7ca762638cdf8cdeceb39755d9c745aff7a64c8789be96ddf6e96/aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0", size = 743409, upload-time = "2025-10-28T20:56:00.354Z" }, - { url = "https://files.pythonhosted.org/packages/99/3d/91524b905ec473beaf35158d17f82ef5a38033e5809fe8742e3657cdbb97/aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb", size = 497006, upload-time = "2025-10-28T20:56:01.85Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d3/7f68bc02a67716fe80f063e19adbd80a642e30682ce74071269e17d2dba1/aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9", size = 493195, upload-time = "2025-10-28T20:56:03.314Z" }, - { url = "https://files.pythonhosted.org/packages/98/31/913f774a4708775433b7375c4f867d58ba58ead833af96c8af3621a0d243/aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613", size = 1747759, upload-time = "2025-10-28T20:56:04.904Z" }, - { url = "https://files.pythonhosted.org/packages/e8/63/04efe156f4326f31c7c4a97144f82132c3bb21859b7bb84748d452ccc17c/aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead", size = 1704456, upload-time = "2025-10-28T20:56:06.986Z" }, - { url = "https://files.pythonhosted.org/packages/8e/02/4e16154d8e0a9cf4ae76f692941fd52543bbb148f02f098ca73cab9b1c1b/aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780", size = 1807572, upload-time = "2025-10-28T20:56:08.558Z" }, - { url = "https://files.pythonhosted.org/packages/34/58/b0583defb38689e7f06798f0285b1ffb3a6fb371f38363ce5fd772112724/aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a", size = 1895954, upload-time = "2025-10-28T20:56:10.545Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f3/083907ee3437425b4e376aa58b2c915eb1a33703ec0dc30040f7ae3368c6/aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592", size = 1747092, upload-time = "2025-10-28T20:56:12.118Z" }, - { url = "https://files.pythonhosted.org/packages/ac/61/98a47319b4e425cc134e05e5f3fc512bf9a04bf65aafd9fdcda5d57ec693/aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab", size = 1606815, upload-time = "2025-10-28T20:56:14.191Z" }, - { url = "https://files.pythonhosted.org/packages/97/4b/e78b854d82f66bb974189135d31fce265dee0f5344f64dd0d345158a5973/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30", size = 1723789, upload-time = "2025-10-28T20:56:16.101Z" }, - { url = "https://files.pythonhosted.org/packages/ed/fc/9d2ccc794fc9b9acd1379d625c3a8c64a45508b5091c546dea273a41929e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40", size = 1718104, upload-time = "2025-10-28T20:56:17.655Z" }, - { url = "https://files.pythonhosted.org/packages/66/65/34564b8765ea5c7d79d23c9113135d1dd3609173da13084830f1507d56cf/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948", size = 1785584, upload-time = "2025-10-28T20:56:19.238Z" }, - { url = "https://files.pythonhosted.org/packages/30/be/f6a7a426e02fc82781afd62016417b3948e2207426d90a0e478790d1c8a4/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf", size = 1595126, upload-time = "2025-10-28T20:56:20.836Z" }, - { url = "https://files.pythonhosted.org/packages/e5/c7/8e22d5d28f94f67d2af496f14a83b3c155d915d1fe53d94b66d425ec5b42/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782", size = 1800665, upload-time = "2025-10-28T20:56:22.922Z" }, - { url = "https://files.pythonhosted.org/packages/d1/11/91133c8b68b1da9fc16555706aa7276fdf781ae2bb0876c838dd86b8116e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8", size = 1739532, upload-time = "2025-10-28T20:56:25.924Z" }, - { url = "https://files.pythonhosted.org/packages/17/6b/3747644d26a998774b21a616016620293ddefa4d63af6286f389aedac844/aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec", size = 431876, upload-time = "2025-10-28T20:56:27.524Z" }, - { url = "https://files.pythonhosted.org/packages/c3/63/688462108c1a00eb9f05765331c107f95ae86f6b197b865d29e930b7e462/aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c", size = 456205, upload-time = "2025-10-28T20:56:29.062Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, -] - -[[package]] -name = "alabaster" -version = "0.7.16" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776, upload-time = "2024-01-10T00:56:10.189Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511, upload-time = "2024-01-10T00:56:08.388Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "antlr4-python3-runtime" -version = "4.9.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d19459005ca000b6e7012f2f1ca597746cbcd1fbfe5e/antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b", size = 117034, upload-time = "2021-11-06T17:52:23.524Z" } - -[[package]] -name = "anyio" -version = "4.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, -] - -[[package]] -name = "apache-beam" -version = "2.56.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cloudpickle" }, - { name = "crcmod" }, - { name = "dill" }, - { name = "fastavro" }, - { name = "fasteners" }, - { name = "grpcio" }, - { name = "hdfs" }, - { name = "httplib2" }, - { name = "js2py" }, - { name = "jsonpickle" }, - { name = "jsonschema" }, - { name = "numpy" }, - { name = "objsize" }, - { name = "orjson" }, - { name = "packaging" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "pyarrow" }, - { name = "pyarrow-hotfix" }, - { name = "pydot" }, - { name = "pymongo" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "redis" }, - { name = "regex" }, - { name = "requests" }, - { name = "typing-extensions" }, - { name = "zstandard" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2f/f0/1e7e785be49727af70d82ec3466c3b83483105f70715e0163b638c72b82f/apache_beam-2.56.0.tar.gz", hash = "sha256:4d9f38ff287757a3d7045a96ecad4bf825e2fb1ca0b9da334927d7cc8b75b250", size = 2447062, upload-time = "2024-05-02T01:12:04.686Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/59/ca/60ffcd51f279c94adee008c0a86e0b06a0f76df5db1ab020691f97b8f6ed/apache_beam-2.56.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3359a5c3d53685346a92b328b3d1783db81fe74284720778d0ba3fa9bd4ce36", size = 5359773, upload-time = "2024-05-02T01:11:13.171Z" }, - { url = "https://files.pythonhosted.org/packages/8f/92/0d92125e17ec0077bdd1b3eee0722e7101c673b095fe35c22d093226841f/apache_beam-2.56.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:792aa9a6cbeeac75166065981a14f84e4a48cdd7967875496fea304f19a87f56", size = 15388561, upload-time = "2024-05-02T01:11:15.828Z" }, - { url = "https://files.pythonhosted.org/packages/39/28/960119472cb379a1408408ccf9c51a5b55198adc5b3829a4e924ffa0f3cb/apache_beam-2.56.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fa8c1aa4227b7c230a9f28b6bf8ccde26192e834a8ad1abe86048ede9e084a8", size = 14930223, upload-time = "2024-05-02T01:11:18.993Z" }, - { url = "https://files.pythonhosted.org/packages/31/73/56021e4e37676b3546440298661e37dde6a703b26f98a3df5ce75759f7f0/apache_beam-2.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26cc3ba00eb3ef45a106431f49ba944ccc93f28491eeedb6d7ed76c75ca39f1a", size = 15496789, upload-time = "2024-05-02T01:11:22.328Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4c/05a85bd3b65655c2bca13c8707b231e7e68268505909a774dea70bebe8f3/apache_beam-2.56.0-cp311-cp311-win32.whl", hash = "sha256:1ccc5ef981790b2a79ac3e6de4c130f8d2ee19740ee0b0619c79d3a9cf94a737", size = 4817184, upload-time = "2024-05-02T01:11:25.533Z" }, - { url = "https://files.pythonhosted.org/packages/f4/b9/dad915b0c914e22a8f8f7212310be23929e72e77e525cc97e1cd939b513a/apache_beam-2.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:ebe29410b1f4e9b65cae7b652d8956b5472a0585dcecf6bd810df6b76e49c4f8", size = 5031949, upload-time = "2024-05-02T01:11:27.659Z" }, -] - -[package.optional-dependencies] -gcp = [ - { name = "cachetools" }, - { name = "google-api-core" }, - { name = "google-apitools" }, - { name = "google-auth" }, - { name = "google-auth-httplib2" }, - { name = "google-cloud-aiplatform" }, - { name = "google-cloud-bigquery" }, - { name = "google-cloud-bigquery-storage" }, - { name = "google-cloud-bigtable" }, - { name = "google-cloud-core" }, - { name = "google-cloud-datastore" }, - { name = "google-cloud-dlp" }, - { name = "google-cloud-language" }, - { name = "google-cloud-pubsub" }, - { name = "google-cloud-pubsublite" }, - { name = "google-cloud-recommendations-ai" }, - { name = "google-cloud-spanner" }, - { name = "google-cloud-storage" }, - { name = "google-cloud-videointelligence" }, - { name = "google-cloud-vision" }, -] - -[[package]] -name = "appnope" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, -] - -[[package]] -name = "argo-workflows" -version = "6.6.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ed/011b97eca0ce38745c1c92f83c461097f6c0face0d53eb6a46dfc355cb0f/argo_workflows-6.6.12.tar.gz", hash = "sha256:3e268c896834eb9554dbb8bb865be66425ffbe5cb4d99a5fde47e13cb7718ab2", size = 286644, upload-time = "2025-10-14T10:33:45.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/a3/90364d83c2544d267b4302489bb22b4f364cfa0f7ca61395bde58ee6c25e/argo_workflows-6.6.12-py3-none-any.whl", hash = "sha256:6bee34fab131692caf44bca93e2885cdb8e3592a54750a231091d05e634bb341", size = 1262778, upload-time = "2025-10-14T10:33:43.757Z" }, -] - -[[package]] -name = "astroid" -version = "3.3.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/74/dfb75f9ccd592bbedb175d4a32fc643cf569d7c218508bfbd6ea7ef9c091/astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce", size = 400439, upload-time = "2025-07-13T18:04:23.177Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/0f/3b8fdc946b4d9cc8cc1e8af42c4e409468c84441b933d037e101b3d72d86/astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec", size = 275612, upload-time = "2025-07-13T18:04:21.07Z" }, -] - -[[package]] -name = "asttokens" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, -] - -[[package]] -name = "astunparse" -version = "1.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, - { name = "wheel" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/af/4182184d3c338792894f34a62672919db7ca008c89abee9b564dd34d8029/astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872", size = 18290, upload-time = "2019-12-22T18:12:13.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/03/13dde6512ad7b4557eb792fbcf0c653af6076b81e5941d36ec61f7ce6028/astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8", size = 12732, upload-time = "2019-12-22T18:12:11.297Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, -] - -[[package]] -name = "babel" -version = "2.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, -] - -[[package]] -name = "beautifulsoup4" -version = "4.14.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" }, -] - -[[package]] -name = "bleach" -version = "6.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, -] - -[package.optional-dependencies] -css = [ - { name = "tinycss2" }, -] - -[[package]] -name = "cachetools" -version = "5.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, -] - -[[package]] -name = "certifi" -version = "2025.10.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, -] - -[[package]] -name = "cffi" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, - { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, - { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, - { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, -] - -[[package]] -name = "cfgv" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, -] - -[[package]] -name = "chardet" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, - { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, - { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, - { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, - { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, - { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, - { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, - { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, - { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, - { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, - { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, - { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, - { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, - { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, - { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, -] - -[[package]] -name = "click" -version = "8.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, -] - -[[package]] -name = "cloudpickle" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5f/51/913ecca3970a2227cf4d5e8937df52cc28f465ac442216110b8e3323262d/cloudpickle-2.2.1.tar.gz", hash = "sha256:d89684b8de9e34a2a43b3460fbca07d09d6e25ce858df4d5a44240403b6178f5", size = 60800, upload-time = "2023-01-19T09:27:28.318Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/80/44286939ca215e88fa827b2aeb6fa3fd2b4a7af322485c7170d6f9fd96e0/cloudpickle-2.2.1-py3-none-any.whl", hash = "sha256:61f594d1f4c295fa5cd9014ceb3a1fc4a70b0de1164b94fbc2d854ccba056f9f", size = 25944, upload-time = "2023-01-19T09:27:26.341Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "comm" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, -] - -[[package]] -name = "contourpy" -version = "1.3.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, - { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, - { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, - { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, - { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, - { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, - { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, - { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, - { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, - { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, - { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, - { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, - { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, - { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, - { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, -] - -[[package]] -name = "crcmod" -version = "1.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c3bcd6c33d2473c1918e0b7f6826a043ca1245dd4e5b/crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e", size = 89670, upload-time = "2010-06-27T14:35:29.538Z" } - -[[package]] -name = "cycler" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, -] - -[[package]] -name = "debugpy" -version = "1.8.17" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129, upload-time = "2025-09-17T16:33:20.633Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/53/3af72b5c159278c4a0cf4cffa518675a0e73bdb7d1cac0239b815502d2ce/debugpy-1.8.17-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:d3fce3f0e3de262a3b67e69916d001f3e767661c6e1ee42553009d445d1cd840", size = 2207154, upload-time = "2025-09-17T16:33:29.457Z" }, - { url = "https://files.pythonhosted.org/packages/8f/6d/204f407df45600e2245b4a39860ed4ba32552330a0b3f5f160ae4cc30072/debugpy-1.8.17-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:c6bdf134457ae0cac6fb68205776be635d31174eeac9541e1d0c062165c6461f", size = 3170322, upload-time = "2025-09-17T16:33:30.837Z" }, - { url = "https://files.pythonhosted.org/packages/f2/13/1b8f87d39cf83c6b713de2620c31205299e6065622e7dd37aff4808dd410/debugpy-1.8.17-cp311-cp311-win32.whl", hash = "sha256:e79a195f9e059edfe5d8bf6f3749b2599452d3e9380484cd261f6b7cd2c7c4da", size = 5155078, upload-time = "2025-09-17T16:33:33.331Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c5/c012c60a2922cc91caa9675d0ddfbb14ba59e1e36228355f41cab6483469/debugpy-1.8.17-cp311-cp311-win_amd64.whl", hash = "sha256:b532282ad4eca958b1b2d7dbcb2b7218e02cb934165859b918e3b6ba7772d3f4", size = 5179011, upload-time = "2025-09-17T16:33:35.711Z" }, - { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210, upload-time = "2025-09-17T16:34:25.835Z" }, -] - -[[package]] -name = "decorator" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, -] - -[[package]] -name = "defusedxml" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, -] - -[[package]] -name = "dill" -version = "0.3.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/11/345f3173809cea7f1a193bfbf02403fff250a3360e0e118a1630985e547d/dill-0.3.1.1.tar.gz", hash = "sha256:42d8ef819367516592a825746a18073ced42ca169ab1f5f4044134703e7a049c", size = 151986, upload-time = "2019-09-28T15:44:19.775Z" } - -[[package]] -name = "distlib" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, -] - -[[package]] -name = "dnspython" -version = "2.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, -] - -[[package]] -name = "docopt" -version = "0.6.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } - -[[package]] -name = "docstring-parser" -version = "0.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, -] - -[[package]] -name = "docutils" -version = "0.20.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/53/a5da4f2c5739cf66290fac1431ee52aff6851c7c8ffd8264f13affd7bcdd/docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b", size = 2058365, upload-time = "2023-05-16T23:39:19.748Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/87/f238c0670b94533ac0353a4e2a1a771a0cc73277b88bff23d3ae35a256c1/docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", size = 572666, upload-time = "2023-05-16T23:39:15.976Z" }, -] - -[[package]] -name = "executing" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, -] - -[[package]] -name = "fastavro" -version = "1.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz", hash = "sha256:2f285be49e45bc047ab2f6bed040bb349da85db3f3c87880e4b92595ea093b2b", size = 1025661, upload-time = "2025-10-10T15:40:55.41Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e9/31c64b47cefc0951099e7c0c8c8ea1c931edd1350f34d55c27cbfbb08df1/fastavro-1.12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b632b713bc5d03928a87d811fa4a11d5f25cd43e79c161e291c7d3f7aa740fd", size = 1016585, upload-time = "2025-10-10T15:41:13.717Z" }, - { url = "https://files.pythonhosted.org/packages/10/76/111560775b548f5d8d828c1b5285ff90e2d2745643fb80ecbf115344eea4/fastavro-1.12.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa7ab3769beadcebb60f0539054c7755f63bd9cf7666e2c15e615ab605f89a8", size = 3404629, upload-time = "2025-10-10T15:41:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/b0/07/6bb93cb963932146c2b6c5c765903a0a547ad9f0f8b769a4a9aad8c06369/fastavro-1.12.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123fb221df3164abd93f2d042c82f538a1d5a43ce41375f12c91ce1355a9141e", size = 3428594, upload-time = "2025-10-10T15:41:17.779Z" }, - { url = "https://files.pythonhosted.org/packages/d1/67/8115ec36b584197ea737ec79e3499e1f1b640b288d6c6ee295edd13b80f6/fastavro-1.12.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:632a4e3ff223f834ddb746baae0cc7cee1068eb12c32e4d982c2fee8a5b483d0", size = 3344145, upload-time = "2025-10-10T15:41:19.89Z" }, - { url = "https://files.pythonhosted.org/packages/9e/9e/a7cebb3af967e62539539897c10138fa0821668ec92525d1be88a9cd3ee6/fastavro-1.12.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:83e6caf4e7a8717d932a3b1ff31595ad169289bbe1128a216be070d3a8391671", size = 3431942, upload-time = "2025-10-10T15:41:22.076Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d1/7774ddfb8781c5224294c01a593ebce2ad3289b948061c9701bd1903264d/fastavro-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:b91a0fe5a173679a6c02d53ca22dcaad0a2c726b74507e0c1c2e71a7c3f79ef9", size = 450542, upload-time = "2025-10-10T15:41:23.333Z" }, -] - -[[package]] -name = "fasteners" -version = "0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/18/7881a99ba5244bfc82f06017316ffe93217dbbbcfa52b887caa1d4f2a6d3/fasteners-0.20.tar.gz", hash = "sha256:55dce8792a41b56f727ba6e123fcaee77fd87e638a6863cec00007bfea84c8d8", size = 25087, upload-time = "2025-08-11T10:19:37.785Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl", hash = "sha256:9422c40d1e350e4259f509fb2e608d6bc43c0136f79a00db1b49046029d0b3b7", size = 18702, upload-time = "2025-08-11T10:19:35.716Z" }, -] - -[[package]] -name = "fastjsonschema" -version = "2.21.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, -] - -[[package]] -name = "fbgemm-gpu" -version = "1.3.0+cpu" -source = { registry = "https://download.pytorch.org/whl/cpu" } -resolution-markers = [ - "sys_platform != 'darwin'", -] -dependencies = [ - { name = "numpy", marker = "sys_platform != 'darwin'" }, -] -wheels = [ - { url = "https://download-r2.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4154e803ba762906a604a72aa41685fdd49459fce55cea79d42ac7c45c8770ca" }, - { url = "https://download-r2.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0267ec844b43028f4b9b8e14acd16276e82bb97f91b6b1078f732eb9225b20c6" }, -] - -[[package]] -name = "fbgemm-gpu" -version = "1.3.0+cu128" -source = { registry = "https://download.pytorch.org/whl/cu128" } -dependencies = [ - { name = "numpy" }, -] -wheels = [ - { url = "https://download-r2.pytorch.org/whl/cu128/fbgemm_gpu-1.3.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:365a2c7f89e89f6d8acf3af5101cbb1651cd1cc64057fd2902feae490814cee3" }, -] - -[[package]] -name = "filelock" -version = "3.20.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, -] - -[[package]] -name = "flatbuffers" -version = "25.9.23" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/1f/3ee70b0a55137442038f2a33469cc5fddd7e0ad2abf83d7497c18a2b6923/flatbuffers-25.9.23.tar.gz", hash = "sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12", size = 22067, upload-time = "2025-09-24T05:25:30.106Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/1b/00a78aa2e8fbd63f9af08c9c19e6deb3d5d66b4dda677a0f61654680ee89/flatbuffers-25.9.23-py2.py3-none-any.whl", hash = "sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2", size = 30869, upload-time = "2025-09-24T05:25:28.912Z" }, -] - -[[package]] -name = "fonttools" -version = "4.60.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823, upload-time = "2025-09-29T21:13:27.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/85/639aa9bface1537e0fb0f643690672dde0695a5bbbc90736bc571b0b1941/fonttools-4.60.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f", size = 2831872, upload-time = "2025-09-29T21:11:20.329Z" }, - { url = "https://files.pythonhosted.org/packages/6b/47/3c63158459c95093be9618794acb1067b3f4d30dcc5c3e8114b70e67a092/fonttools-4.60.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2", size = 2356990, upload-time = "2025-09-29T21:11:22.754Z" }, - { url = "https://files.pythonhosted.org/packages/94/dd/1934b537c86fcf99f9761823f1fc37a98fbd54568e8e613f29a90fed95a9/fonttools-4.60.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914", size = 5042189, upload-time = "2025-09-29T21:11:25.061Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d2/9f4e4c4374dd1daa8367784e1bd910f18ba886db1d6b825b12edf6db3edc/fonttools-4.60.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1", size = 4978683, upload-time = "2025-09-29T21:11:27.693Z" }, - { url = "https://files.pythonhosted.org/packages/cc/c4/0fb2dfd1ecbe9a07954cc13414713ed1eab17b1c0214ef07fc93df234a47/fonttools-4.60.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d", size = 5021372, upload-time = "2025-09-29T21:11:30.257Z" }, - { url = "https://files.pythonhosted.org/packages/0c/d5/495fc7ae2fab20223cc87179a8f50f40f9a6f821f271ba8301ae12bb580f/fonttools-4.60.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa", size = 5132562, upload-time = "2025-09-29T21:11:32.737Z" }, - { url = "https://files.pythonhosted.org/packages/bc/fa/021dab618526323c744e0206b3f5c8596a2e7ae9aa38db5948a131123e83/fonttools-4.60.1-cp311-cp311-win32.whl", hash = "sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258", size = 2230288, upload-time = "2025-09-29T21:11:35.015Z" }, - { url = "https://files.pythonhosted.org/packages/bb/78/0e1a6d22b427579ea5c8273e1c07def2f325b977faaf60bb7ddc01456cb1/fonttools-4.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf", size = 2278184, upload-time = "2025-09-29T21:11:37.434Z" }, - { url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175, upload-time = "2025-09-29T21:13:24.134Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, - { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, - { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, - { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, - { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, - { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, - { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, - { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, - { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, - { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, - { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, - { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, - { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, - { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, -] - -[[package]] -name = "fsspec" -version = "2025.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, -] - -[[package]] -name = "gast" -version = "0.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3c/14/c566f5ca00c115db7725263408ff952b8ae6d6a4e792ef9c84e77d9af7a1/gast-0.6.0.tar.gz", hash = "sha256:88fc5300d32c7ac6ca7b515310862f71e6fdf2c029bbec7c66c0f5dd47b6b1fb", size = 27708, upload-time = "2024-06-27T20:31:49.527Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/61/8001b38461d751cd1a0c3a6ae84346796a5758123f3ed97a1b121dfbf4f3/gast-0.6.0-py3-none-any.whl", hash = "sha256:52b182313f7330389f72b069ba00f174cfe2a06411099547288839c6cbafbd54", size = 21173, upload-time = "2024-07-09T13:15:15.615Z" }, -] - -[[package]] -name = "gigl" -version = "0.2.0" -source = { editable = "." } -dependencies = [ - { name = "argo-workflows" }, - { name = "chardet" }, - { name = "google-cloud-aiplatform" }, - { name = "google-cloud-dataproc" }, - { name = "google-cloud-logging" }, - { name = "google-cloud-pipeline-components" }, - { name = "google-cloud-storage" }, - { name = "ipykernel" }, - { name = "ipython" }, - { name = "kfp" }, - { name = "matplotlib" }, - { name = "mmh3" }, - { name = "msgpack" }, - { name = "nbconvert" }, - { name = "nbformat" }, - { name = "numpy" }, - { name = "omegaconf" }, - { name = "pandas" }, - { name = "pip" }, - { name = "protobuf" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "scikit-learn" }, - { name = "tensorflow" }, -] - -[package.optional-dependencies] -experimental = [ - { name = "hydra-core" }, -] -pyg27-torch28-cpu = [ - { name = "fbgemm-gpu", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, - { name = "pyg-lib", version = "0.5.0+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch", version = "2.8.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch-cluster", version = "1.6.3+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch-geometric" }, - { name = "torch-scatter", version = "2.1.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch-sparse", version = "0.6.18+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch-spline-conv", version = "1.2.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torchrec", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, -] -pyg27-torch28-cu128 = [ - { name = "fbgemm-gpu", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, - { name = "pyg-lib", version = "0.5.0+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, - { name = "torch-cluster", version = "1.6.3+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch-geometric", marker = "sys_platform != 'darwin'" }, - { name = "torch-scatter", version = "2.1.2+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch-sparse", version = "0.6.18+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torch-spline-conv", version = "1.2.2+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torchrec", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, -] -transform = [ - { name = "apache-beam", extra = ["gcp"] }, - { name = "pyarrow" }, - { name = "tensorflow-data-validation", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow-transform", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tfx-bsl", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] - -[package.dev-dependencies] -cpp-build = [ - { name = "pybind11" }, - { name = "scikit-build-core" }, -] -dev = [ - { name = "astroid" }, - { name = "mdformat" }, - { name = "mdformat-tables" }, - { name = "mistune" }, - { name = "mypy" }, - { name = "mypy-extensions" }, - { name = "mypy-protobuf" }, - { name = "myst-nb" }, - { name = "myst-parser" }, - { name = "nbconvert" }, - { name = "nbsphinx" }, - { name = "pandas-stubs" }, - { name = "parameterized" }, - { name = "pre-commit" }, - { name = "pybind11" }, - { name = "pydata-sphinx-theme" }, - { name = "ruff" }, - { name = "scikit-build-core" }, - { name = "sphinx" }, - { name = "sphinx-autoapi" }, - { name = "sphinx-autodoc-typehints" }, - { name = "sphinx-copybutton" }, - { name = "sphinx-design" }, - { name = "sphinx-hoverxref" }, - { name = "sphinx-rtd-theme" }, - { name = "sphinx-tabs" }, - { name = "types-psutil" }, - { name = "types-pyyaml" }, - { name = "types-requests" }, - { name = "types-tqdm" }, -] -docs = [ - { name = "astroid" }, - { name = "mistune" }, - { name = "myst-nb" }, - { name = "myst-parser" }, - { name = "nbconvert" }, - { name = "nbsphinx" }, - { name = "pydata-sphinx-theme" }, - { name = "sphinx" }, - { name = "sphinx-autoapi" }, - { name = "sphinx-autodoc-typehints" }, - { name = "sphinx-copybutton" }, - { name = "sphinx-design" }, - { name = "sphinx-hoverxref" }, - { name = "sphinx-rtd-theme" }, - { name = "sphinx-tabs" }, -] -lint = [ - { name = "mdformat" }, - { name = "mdformat-tables" }, - { name = "mypy" }, - { name = "mypy-extensions" }, - { name = "mypy-protobuf" }, - { name = "ruff" }, -] -test = [ - { name = "parameterized" }, -] -typing-stubs = [ - { name = "pandas-stubs" }, - { name = "types-psutil" }, - { name = "types-pyyaml" }, - { name = "types-requests" }, - { name = "types-tqdm" }, -] - -[package.metadata] -requires-dist = [ - { name = "apache-beam", extras = ["gcp"], marker = "extra == 'transform'", specifier = "==2.56.0" }, - { name = "argo-workflows" }, - { name = "chardet" }, - { name = "fbgemm-gpu", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", specifier = "~=1.3.0", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "fbgemm-gpu", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", specifier = "~=1.3.0", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, - { name = "google-cloud-aiplatform" }, - { name = "google-cloud-dataproc" }, - { name = "google-cloud-logging" }, - { name = "google-cloud-pipeline-components" }, - { name = "google-cloud-storage" }, - { name = "hydra-core", marker = "extra == 'experimental'", specifier = "==1.3.2" }, - { name = "ipykernel" }, - { name = "ipython" }, - { name = "kfp", specifier = ">=2.0.0" }, - { name = "matplotlib" }, - { name = "mmh3" }, - { name = "msgpack" }, - { name = "nbconvert" }, - { name = "nbformat" }, - { name = "numpy" }, - { name = "omegaconf", specifier = ">=2.3.0,<3.0.0" }, - { name = "pandas" }, - { name = "pip", specifier = "~=25.3" }, - { name = "protobuf" }, - { name = "pyarrow", marker = "extra == 'transform'", specifier = "==10.0.1" }, - { name = "pyg-lib", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "pyg-lib", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "scikit-learn" }, - { name = "tensorflow", specifier = "~=2.16" }, - { name = "tensorflow-data-validation", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.1" }, - { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.1" }, - { name = "tensorflow-transform", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.0" }, - { name = "tfx-bsl", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.1" }, - { name = "torch", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", specifier = "==2.8", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, - { name = "torch", marker = "extra == 'pyg27-torch28-cpu'", specifier = "==2.8", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "torch-cluster", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "torch-cluster", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, - { name = "torch-geometric", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", specifier = "==2.7" }, - { name = "torch-geometric", marker = "extra == 'pyg27-torch28-cpu'", specifier = "==2.7" }, - { name = "torch-scatter", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "torch-scatter", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, - { name = "torch-sparse", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "torch-sparse", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, - { name = "torch-spline-conv", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "torch-spline-conv", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, - { name = "torchrec", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, - { name = "torchrec", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, -] -provides-extras = ["transform", "pyg27-torch28-cpu", "pyg27-torch28-cu128", "experimental"] - -[package.metadata.requires-dev] -cpp-build = [ - { name = "pybind11", specifier = ">=2.12" }, - { name = "scikit-build-core", specifier = ">=0.10" }, -] -dev = [ - { name = "astroid", specifier = "==3.3.11" }, - { name = "mdformat", specifier = "==0.7.22" }, - { name = "mdformat-tables", specifier = "==1.0.0" }, - { name = "mistune", specifier = ">=2.0.3" }, - { name = "mypy", specifier = "==1.8.0" }, - { name = "mypy-extensions" }, - { name = "mypy-protobuf", specifier = "==3.3.0" }, - { name = "myst-nb", specifier = "==1.2.0" }, - { name = "myst-parser", specifier = "==2.0.0" }, - { name = "nbconvert", specifier = ">=7.16.2" }, - { name = "nbsphinx", specifier = "==0.9.3" }, - { name = "pandas-stubs", specifier = "==2.2.2.240807" }, - { name = "parameterized", specifier = "==0.9.0" }, - { name = "pre-commit", specifier = "==3.3.2" }, - { name = "pybind11", specifier = ">=2.12" }, - { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, - { name = "ruff", specifier = "==0.15.10" }, - { name = "scikit-build-core", specifier = ">=0.10" }, - { name = "sphinx", specifier = "==7.4.7" }, - { name = "sphinx-autoapi", specifier = "==3.6.0" }, - { name = "sphinx-autodoc-typehints", specifier = "==2.3.0" }, - { name = "sphinx-copybutton", specifier = "==0.5.2" }, - { name = "sphinx-design", specifier = "==0.6.0" }, - { name = "sphinx-hoverxref", specifier = "==1.3.0" }, - { name = "sphinx-rtd-theme", specifier = "==2.0.0" }, - { name = "sphinx-tabs", specifier = "==3.4.5" }, - { name = "types-psutil", specifier = "==7.0.0.20250401" }, - { name = "types-pyyaml", specifier = "~=6.0.12" }, - { name = "types-requests", specifier = "==2.31.0.6" }, - { name = "types-tqdm", specifier = "==4.67.0.20250513" }, -] -docs = [ - { name = "astroid", specifier = "==3.3.11" }, - { name = "mistune", specifier = ">=2.0.3" }, - { name = "myst-nb", specifier = "==1.2.0" }, - { name = "myst-parser", specifier = "==2.0.0" }, - { name = "nbconvert", specifier = ">=7.16.2" }, - { name = "nbsphinx", specifier = "==0.9.3" }, - { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, - { name = "sphinx", specifier = "==7.4.7" }, - { name = "sphinx-autoapi", specifier = "==3.6.0" }, - { name = "sphinx-autodoc-typehints", specifier = "==2.3.0" }, - { name = "sphinx-copybutton", specifier = "==0.5.2" }, - { name = "sphinx-design", specifier = "==0.6.0" }, - { name = "sphinx-hoverxref", specifier = "==1.3.0" }, - { name = "sphinx-rtd-theme", specifier = "==2.0.0" }, - { name = "sphinx-tabs", specifier = "==3.4.5" }, -] -lint = [ - { name = "mdformat", specifier = "==0.7.22" }, - { name = "mdformat-tables", specifier = "==1.0.0" }, - { name = "mypy", specifier = "==1.8.0" }, - { name = "mypy-extensions" }, - { name = "mypy-protobuf", specifier = "==3.3.0" }, - { name = "ruff", specifier = "==0.15.10" }, -] -test = [{ name = "parameterized", specifier = "==0.9.0" }] -typing-stubs = [ - { name = "pandas-stubs", specifier = "==2.2.2.240807" }, - { name = "types-psutil", specifier = "==7.0.0.20250401" }, - { name = "types-pyyaml", specifier = "~=6.0.12" }, - { name = "types-requests", specifier = "==2.31.0.6" }, - { name = "types-tqdm", specifier = "==4.67.0.20250513" }, -] - -[[package]] -name = "google-api-core" -version = "2.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-auth" }, - { name = "googleapis-common-protos" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759, upload-time = "2025-10-28T21:34:51.529Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706, upload-time = "2025-10-28T21:34:50.151Z" }, -] - -[package.optional-dependencies] -grpc = [ - { name = "grpcio" }, - { name = "grpcio-status" }, -] - -[[package]] -name = "google-api-python-client" -version = "1.12.11" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "google-auth", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "google-auth-httplib2", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "httplib2", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "six", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "uritemplate", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dd/12/07e966db6bfa4bd440af2f83ca6cc7bd61c2f4859992b7103437e8a98ce1/google-api-python-client-1.12.11.tar.gz", hash = "sha256:1b4bd42a46321e13c0542a9e4d96fa05d73626f07b39f83a73a947d70ca706a9", size = 146876, upload-time = "2022-03-15T13:49:56.711Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/ba/6f9604c5dadd024ec0a2f6d1789f7fbec3d53c570277966ab7376022c3d6/google_api_python_client-1.12.11-py2.py3-none-any.whl", hash = "sha256:7e0a1a265c8d3088ee1987778c72683fcb376e32bada8d7767162bd9c503fd9b", size = 62077, upload-time = "2022-03-15T13:49:54.84Z" }, -] - -[[package]] -name = "google-apitools" -version = "0.5.31" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fasteners" }, - { name = "httplib2" }, - { name = "oauth2client" }, - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/19/da/aefc4cf4c168b5d875344cd9dddc77e3a2d11986b630251af5ce47dd2843/google-apitools-0.5.31.tar.gz", hash = "sha256:4af0dd6dd4582810690251f0b57a97c1873dadfda54c5bc195844c8907624170", size = 173463, upload-time = "2020-05-14T17:25:19.126Z" } - -[[package]] -name = "google-auth" -version = "2.42.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachetools" }, - { name = "pyasn1-modules" }, - { name = "rsa" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/25/6b/22a77135757c3a7854c9f008ffed6bf4e8851616d77faf13147e9ab5aae6/google_auth-2.42.1.tar.gz", hash = "sha256:30178b7a21aa50bffbdc1ffcb34ff770a2f65c712170ecd5446c4bef4dc2b94e", size = 295541, upload-time = "2025-10-30T16:42:19.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/05/adeb6c495aec4f9d93f9e2fc29eeef6e14d452bba11d15bdb874ce1d5b10/google_auth-2.42.1-py2.py3-none-any.whl", hash = "sha256:eb73d71c91fc95dbd221a2eb87477c278a355e7367a35c0d84e6b0e5f9b4ad11", size = 222550, upload-time = "2025-10-30T16:42:17.878Z" }, -] - -[[package]] -name = "google-auth-httplib2" -version = "0.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-auth" }, - { name = "httplib2" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e0/83/7ef576d1c7ccea214e7b001e69c006bc75e058a3a1f2ab810167204b698b/google_auth_httplib2-0.2.1.tar.gz", hash = "sha256:5ef03be3927423c87fb69607b42df23a444e434ddb2555b73b3679793187b7de", size = 11086, upload-time = "2025-10-30T21:13:16.569Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/a7/ca23dd006255f70e2bc469d3f9f0c82ea455335bfd682ad4d677adc435de/google_auth_httplib2-0.2.1-py3-none-any.whl", hash = "sha256:1be94c611db91c01f9703e7f62b0a59bbd5587a95571c7b6fade510d648bc08b", size = 9525, upload-time = "2025-10-30T21:13:15.758Z" }, -] - -[[package]] -name = "google-cloud-aiplatform" -version = "1.124.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docstring-parser" }, - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "google-cloud-bigquery" }, - { name = "google-cloud-resource-manager" }, - { name = "google-cloud-storage" }, - { name = "google-genai" }, - { name = "packaging" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "pydantic" }, - { name = "shapely" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d7/ad/a3da0cbb78a933544ef2ca3db3da242a2217a52d823beb3ea129995c00df/google_cloud_aiplatform-1.124.0.tar.gz", hash = "sha256:cf565f2ce3dac19c6502a65d89c89760000fde1d531be54949c6232ba2a168fd", size = 9755170, upload-time = "2025-10-30T19:59:22.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/46/c20db72a9389c5b6595c2c3fed9abe2b05d3658fe2c07657f7324623cb63/google_cloud_aiplatform-1.124.0-py2.py3-none-any.whl", hash = "sha256:047685f0ee0ab7346ba7d437904357077e3362b32a951c5038a9ac789c5f9148", size = 8112493, upload-time = "2025-10-30T19:59:19.42Z" }, -] - -[[package]] -name = "google-cloud-appengine-logging" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/260266e5fa7283b721bbef012f3223d514e2569446f56786fe0c80aa0fd4/google_cloud_appengine_logging-1.7.0.tar.gz", hash = "sha256:ea9ce73430cfc99f8957fd7df97733f9a759d4caab65e19d63a7474f012ffd94", size = 16729, upload-time = "2025-10-17T02:33:40.842Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/45/99bb629a23639d868c693748598796d7f8e60f62289795b6f310d3328b19/google_cloud_appengine_logging-1.7.0-py3-none-any.whl", hash = "sha256:cfd28bc61a030008381a646d112ebe2734bf72abc8c12afc47d035a2c9b041fe", size = 16924, upload-time = "2025-10-17T02:30:48.802Z" }, -] - -[[package]] -name = "google-cloud-audit-log" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "googleapis-common-protos" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/d2/ad96950410f8a05e921a6da2e1a6ba4aeca674bbb5dda8200c3c7296d7ad/google_cloud_audit_log-0.4.0.tar.gz", hash = "sha256:8467d4dcca9f3e6160520c24d71592e49e874838f174762272ec10e7950b6feb", size = 44682, upload-time = "2025-10-17T02:33:44.641Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/25/532886995f11102ad6de290496de5db227bd3a73827702445928ad32edcb/google_cloud_audit_log-0.4.0-py3-none-any.whl", hash = "sha256:6b88e2349df45f8f4cc0993b687109b1388da1571c502dc1417efa4b66ec55e0", size = 44890, upload-time = "2025-10-17T02:30:55.11Z" }, -] - -[[package]] -name = "google-cloud-bigquery" -version = "3.38.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "google-resumable-media" }, - { name = "packaging" }, - { name = "python-dateutil" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/07/b2/a17e40afcf9487e3d17db5e36728ffe75c8d5671c46f419d7b6528a5728a/google_cloud_bigquery-3.38.0.tar.gz", hash = "sha256:8afcb7116f5eac849097a344eb8bfda78b7cfaae128e60e019193dd483873520", size = 503666, upload-time = "2025-09-17T20:33:33.47Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/3c/c8cada9ec282b29232ed9aed5a0b5cca6cf5367cb2ffa8ad0d2583d743f1/google_cloud_bigquery-3.38.0-py3-none-any.whl", hash = "sha256:e06e93ff7b245b239945ef59cb59616057598d369edac457ebf292bd61984da6", size = 259257, upload-time = "2025-09-17T20:33:31.404Z" }, -] - -[[package]] -name = "google-cloud-bigquery-storage" -version = "2.34.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e8/d2/42787f7843c1ebb386f1c54dd8d7cc16dc85d661dca74041626cd5d459e0/google_cloud_bigquery_storage-2.34.0.tar.gz", hash = "sha256:221740a991b3173027ebb0f3aa5f06c65bdf90fc4eb1b71da798093b6bf6d22d", size = 293674, upload-time = "2025-10-28T17:26:30.976Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/7d/b347996d12a9da424eaccbbdcf831be39dfd2f81400fa912804379a5a237/google_cloud_bigquery_storage-2.34.0-py3-none-any.whl", hash = "sha256:5c1b55f2a33bfb0730cf5a2f7e4f0cc6a7166d9026142ab78c2ffd5130884c46", size = 295668, upload-time = "2025-10-28T17:26:19.792Z" }, -] - -[[package]] -name = "google-cloud-bigtable" -version = "2.34.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "google-crc32c" }, - { name = "grpc-google-iam-v1" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/29/20/8a29e1d5858ba76f443dc527a223e769347b915cb060a9f19250241aa38a/google_cloud_bigtable-2.34.0.tar.gz", hash = "sha256:773258b00cd3f9a3a35639cc38bd711f4f1418aaa0c8d70cb028978ed98dc2c2", size = 766606, upload-time = "2025-10-22T19:04:53.645Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/6d/aa44110504b4b9d125f1cc9715b72a178ebbe5cb79698e7a95893c391e56/google_cloud_bigtable-2.34.0-py3-none-any.whl", hash = "sha256:a4a8db4903840cd3f89fb19c060eea2e7c09c1265cb0538cfc11288dbc6000e4", size = 537041, upload-time = "2025-10-22T19:04:52.014Z" }, -] - -[[package]] -name = "google-cloud-core" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, -] - -[[package]] -name = "google-cloud-dataproc" -version = "5.23.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpc-google-iam-v1" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/45/9010c4c1176d745aad3e8832caa752a2b05bd9a8e216ea86f1aae5f72924/google_cloud_dataproc-5.23.0.tar.gz", hash = "sha256:94b385bdbf67b7e2b6f53ca0953ac2df2195e13e131bad132efc866459f606a3", size = 569152, upload-time = "2025-10-17T02:34:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/fa/7e5ebe496c73dbc6291c94b40e1e3062d7ffeb52d8ffd4b13cbcedfd8500/google_cloud_dataproc-5.23.0-py3-none-any.whl", hash = "sha256:2b949b4d4355f25d09707e15cdb065eee93c2ddc21f2dd5c042eafa0dc9f8e0a", size = 484197, upload-time = "2025-10-17T02:32:33.404Z" }, -] - -[[package]] -name = "google-cloud-datastore" -version = "2.21.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6a/e1/82174567df885c78d10af94755443e0d1a69d02309aed55fa3b412297c53/google_cloud_datastore-2.21.0.tar.gz", hash = "sha256:eee454dd4a55f5b327f9f344928ff1a09a6f77c23d5e3d908ad31a13cc2f4073", size = 261373, upload-time = "2025-04-15T01:05:21.033Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/a7/6ecb2f147cb9da8feb5bdbf959d481ca62f2e27106f3446b67dc8a892659/google_cloud_datastore-2.21.0-py2.py3-none-any.whl", hash = "sha256:f303f27cd1983383f20bd227019cd8a7897419e0ec6b878367c58c66245f9d9b", size = 208009, upload-time = "2025-04-15T01:05:19.088Z" }, -] - -[[package]] -name = "google-cloud-dlp" -version = "3.33.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d5/71/8c7f32b222a01ed7ab616e4447ed3eaeec9543ef4afd0e4ea3ca37c4ad96/google_cloud_dlp-3.33.0.tar.gz", hash = "sha256:a910be118ec3c8898c38521610d62f4a16f333a4deb2abeb773e720f6e5f67e3", size = 273468, upload-time = "2025-10-17T02:34:39.622Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/0f/752b2e140568e05d6a11619265a1941f00d25ab98f0c6669017fd86c51c9/google_cloud_dlp-3.33.0-py3-none-any.whl", hash = "sha256:982220c5ae66b93724ef008286ccc7baef33d975b4b1d62f715a2678424a757b", size = 218631, upload-time = "2025-10-17T02:32:46.326Z" }, -] - -[[package]] -name = "google-cloud-language" -version = "2.18.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/ed/59445dde0a3a575ef901c82f07b40bb39056e17e122bae5cc4049b19938c/google_cloud_language-2.18.0.tar.gz", hash = "sha256:75b9535f6b424c9c08fe1ef5d7cce42932591a80da73a1da72c591dfdc69c41e", size = 178780, upload-time = "2025-10-17T02:34:57.766Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/94/64c5e9ae6b312c8034a159ab8e7103a02866dbab1cbe0f76a2b3c3229150/google_cloud_language-2.18.0-py3-none-any.whl", hash = "sha256:d803dd6b10e3696d8bb11ce93a89ff17957e8d1666b1547f86e50867fef1854c", size = 168878, upload-time = "2025-10-17T02:33:15.834Z" }, -] - -[[package]] -name = "google-cloud-logging" -version = "3.12.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "google-cloud-appengine-logging" }, - { name = "google-cloud-audit-log" }, - { name = "google-cloud-core" }, - { name = "grpc-google-iam-v1" }, - { name = "opentelemetry-api" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/14/9c/d42ecc94f795a6545930e5f846a7ae59ff685ded8bc086648dd2bee31a1a/google_cloud_logging-3.12.1.tar.gz", hash = "sha256:36efc823985055b203904e83e1c8f9f999b3c64270bcda39d57386ca4effd678", size = 289569, upload-time = "2025-04-22T20:50:24.71Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/41/f8a3197d39b773a91f335dee36c92ef26a8ec96efe78d64baad89d367df4/google_cloud_logging-3.12.1-py2.py3-none-any.whl", hash = "sha256:6817878af76ec4e7568976772839ab2c43ddfd18fbbf2ce32b13ef549cd5a862", size = 229466, upload-time = "2025-04-22T20:50:23.294Z" }, -] - -[[package]] -name = "google-cloud-pipeline-components" -version = "2.21.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-cloud-aiplatform" }, - { name = "jinja2" }, - { name = "kfp" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/fe/9d572ad5a0d83a8bace621cce2fec4e00b1e60774e245124c41f25614ec3/google_cloud_pipeline_components-2.21.0-py3-none-any.whl", hash = "sha256:33d967541e726cae5466d2e46ca7d1c6e411b8d29a94a296fda13a6d75f9097d", size = 1466141, upload-time = "2025-09-25T21:44:46.235Z" }, -] - -[[package]] -name = "google-cloud-pubsub" -version = "2.33.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpc-google-iam-v1" }, - { name = "grpcio" }, - { name = "grpcio-status" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-sdk" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/dd/6e016dc4c893b8a7eee9f5a4ca8659a886164580bfb129b744f47aff1cde/google_cloud_pubsub-2.33.0.tar.gz", hash = "sha256:83bc50c54f669efb924ad21385bc7092fa11f7576eabef3d0b4d7aa8efa90aa6", size = 393962, upload-time = "2025-10-30T20:13:08.226Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/35/6f341d8b2e94cb61b6ead415e582e3fd697472ccef9bc3972c6d83e6273f/google_cloud_pubsub-2.33.0-py3-none-any.whl", hash = "sha256:d7af3b6448c9adc171f677a989dafb4c67df6112140bd4633f4bf7e3ebe67aa0", size = 321254, upload-time = "2025-10-30T20:13:06.37Z" }, -] - -[[package]] -name = "google-cloud-pubsublite" -version = "1.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-cloud-pubsub" }, - { name = "grpcio" }, - { name = "grpcio-status" }, - { name = "overrides" }, - { name = "proto-plus" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/61/e41160faf2d0348dc4b45e44ace5215395cba61cd7a733ad41a48e7dea03/google_cloud_pubsublite-1.12.0.tar.gz", hash = "sha256:9ab65255ddbb313f46babd510b0eaa3ebd54532b7e99eead948d76e1d28a6f1b", size = 285887, upload-time = "2025-02-24T22:55:07.648Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/74/a2/858881a04f708f3aa5e782ce79ca8b283ed12f9a4c55c8401ef9810b8d12/google_cloud_pubsublite-1.12.0-py2.py3-none-any.whl", hash = "sha256:5c013ebdc3bdee53979f3ca78e331118e58e145dc7c062415b1b60825ceb5625", size = 322029, upload-time = "2025-02-24T22:55:05.39Z" }, -] - -[[package]] -name = "google-cloud-recommendations-ai" -version = "0.10.18" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/46/4b/65546c277002cfb8df14a5fc5e914370fece901eb75f2813b7bbbbbb59e9/google_cloud_recommendations_ai-0.10.18.tar.gz", hash = "sha256:a6bccb45744fd89f038aa3e19502d1f46ea61c438dd2c08528533f8e185ec469", size = 212396, upload-time = "2025-06-11T23:10:29.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/f4/548c455fc0f93ab2ad538c0338cbc79a9d1640b82fcec06ecd2764d95384/google_cloud_recommendations_ai-0.10.18-py3-none-any.whl", hash = "sha256:c5c4b569d8be96e65dc273d18a35e44147ef62f845c8a9e8afd93474802c60c8", size = 212208, upload-time = "2025-06-11T23:10:28.03Z" }, -] - -[[package]] -name = "google-cloud-resource-manager" -version = "1.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpc-google-iam-v1" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/19/b95d0e8814ce42522e434cdd85c0cb6236d874d9adf6685fc8e6d1fda9d1/google_cloud_resource_manager-1.15.0.tar.gz", hash = "sha256:3d0b78c3daa713f956d24e525b35e9e9a76d597c438837171304d431084cedaf", size = 449227, upload-time = "2025-10-20T14:57:01.108Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/93/5aef41a5f146ad4559dd7040ae5fa8e7ddcab4dfadbef6cb4b66d775e690/google_cloud_resource_manager-1.15.0-py3-none-any.whl", hash = "sha256:0ccde5db644b269ddfdf7b407a2c7b60bdbf459f8e666344a5285601d00c7f6d", size = 397151, upload-time = "2025-10-20T14:53:45.409Z" }, -] - -[[package]] -name = "google-cloud-spanner" -version = "3.59.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-cloud-core" }, - { name = "grpc-google-iam-v1" }, - { name = "grpc-interceptor" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "sqlparse" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/62/f0e535875e49b34128710342115681fe1a97f45759e1427307ab150a4caa/google_cloud_spanner-3.59.0.tar.gz", hash = "sha256:dec7a78bfe1f94aef508ff9c61dba4196f3c70c83a0f75c271b4652686d08641", size = 705137, upload-time = "2025-10-23T09:35:49.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/08/1a38139853364b4737e3a0e03a3fd87d60c7545e90a963a8a6457777b5f9/google_cloud_spanner-3.59.0-py3-none-any.whl", hash = "sha256:409ed9746787c9435fd015731a5e3cf6f3ea2995a807c580f4216bb5d464260a", size = 502645, upload-time = "2025-10-23T09:35:47.954Z" }, -] - -[[package]] -name = "google-cloud-storage" -version = "2.19.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "google-crc32c" }, - { name = "google-resumable-media" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/36/76/4d965702e96bb67976e755bed9828fa50306dca003dbee08b67f41dd265e/google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2", size = 5535488, upload-time = "2024-12-05T01:35:06.49Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/94/6db383d8ee1adf45dc6c73477152b82731fa4c4a46d9c1932cc8757e0fd4/google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba", size = 131787, upload-time = "2024-12-05T01:35:04.736Z" }, -] - -[[package]] -name = "google-cloud-videointelligence" -version = "2.17.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ff/c3/039548b7e7a1589c3f816065014a4dddceb9ba33bf5e8b6666b1e6d609ce/google_cloud_videointelligence-2.17.0.tar.gz", hash = "sha256:0008b4e618e3ea835883e032d8660c86c6b933c98fe0bfadda036086ff037284", size = 243662, upload-time = "2025-10-20T14:57:32.816Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/56/d19ef7a2d3f669568046e68ce980c5091e037bdd960d3dae44854bbba437/google_cloud_videointelligence-2.17.0-py3-none-any.whl", hash = "sha256:b294a7e09a0154c02dcaa250e93686a57b76736ba448bd5033692679b6585cf6", size = 276733, upload-time = "2025-10-20T14:55:32.306Z" }, -] - -[[package]] -name = "google-cloud-vision" -version = "3.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e2/83/8a5de5968933671badfffd1738eac489b29c557274d97191a4acbe0a5d9a/google_cloud_vision-3.11.0.tar.gz", hash = "sha256:c3cb57df2cf152ebe62ebaae9b1d5deff5a26aec5bd6e1c7f67e44bf6f4518f4", size = 570943, upload-time = "2025-10-20T14:57:34.107Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/ca/8c5ff6041a081a6271159b2e5d378be69c964da75191ff79ef241c6ccbb3/google_cloud_vision-3.11.0-py3-none-any.whl", hash = "sha256:8910f743a87a34058dd6e5e41790be1eb100a0b91c20cc6372a2388b328c8890", size = 529092, upload-time = "2025-10-20T14:55:33.756Z" }, -] - -[[package]] -name = "google-crc32c" -version = "1.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/ae/87802e6d9f9d69adfaedfcfd599266bf386a54d0be058b532d04c794f76d/google_crc32c-1.7.1.tar.gz", hash = "sha256:2bff2305f98846f3e825dbeec9ee406f89da7962accdb29356e4eadc251bd472", size = 14495, upload-time = "2025-03-26T14:29:13.32Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/94/220139ea87822b6fdfdab4fb9ba81b3fff7ea2c82e2af34adc726085bffc/google_crc32c-1.7.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:6fbab4b935989e2c3610371963ba1b86afb09537fd0c633049be82afe153ac06", size = 30468, upload-time = "2025-03-26T14:32:52.215Z" }, - { url = "https://files.pythonhosted.org/packages/94/97/789b23bdeeb9d15dc2904660463ad539d0318286d7633fe2760c10ed0c1c/google_crc32c-1.7.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:ed66cbe1ed9cbaaad9392b5259b3eba4a9e565420d734e6238813c428c3336c9", size = 30313, upload-time = "2025-03-26T14:57:38.758Z" }, - { url = "https://files.pythonhosted.org/packages/81/b8/976a2b843610c211e7ccb3e248996a61e87dbb2c09b1499847e295080aec/google_crc32c-1.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee6547b657621b6cbed3562ea7826c3e11cab01cd33b74e1f677690652883e77", size = 33048, upload-time = "2025-03-26T14:41:30.679Z" }, - { url = "https://files.pythonhosted.org/packages/c9/16/a3842c2cf591093b111d4a5e2bfb478ac6692d02f1b386d2a33283a19dc9/google_crc32c-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d68e17bad8f7dd9a49181a1f5a8f4b251c6dbc8cc96fb79f1d321dfd57d66f53", size = 32669, upload-time = "2025-03-26T14:41:31.432Z" }, - { url = "https://files.pythonhosted.org/packages/04/17/ed9aba495916fcf5fe4ecb2267ceb851fc5f273c4e4625ae453350cfd564/google_crc32c-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:6335de12921f06e1f774d0dd1fbea6bf610abe0887a1638f64d694013138be5d", size = 33476, upload-time = "2025-03-26T14:29:10.211Z" }, - { url = "https://files.pythonhosted.org/packages/16/1b/1693372bf423ada422f80fd88260dbfd140754adb15cbc4d7e9a68b1cb8e/google_crc32c-1.7.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85fef7fae11494e747c9fd1359a527e5970fc9603c90764843caabd3a16a0a48", size = 28241, upload-time = "2025-03-26T14:41:45.898Z" }, - { url = "https://files.pythonhosted.org/packages/fd/3c/2a19a60a473de48717b4efb19398c3f914795b64a96cf3fbe82588044f78/google_crc32c-1.7.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6efb97eb4369d52593ad6f75e7e10d053cf00c48983f7a973105bc70b0ac4d82", size = 28048, upload-time = "2025-03-26T14:41:46.696Z" }, -] - -[[package]] -name = "google-genai" -version = "1.47.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "google-auth" }, - { name = "httpx" }, - { name = "pydantic" }, - { name = "requests" }, - { name = "tenacity" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/97/784fba9bc6c41263ff90cb9063eadfdd755dde79cfa5a8d0e397b067dcf9/google_genai-1.47.0.tar.gz", hash = "sha256:ecece00d0a04e6739ea76cc8dad82ec9593d9380aaabef078990e60574e5bf59", size = 241471, upload-time = "2025-10-29T22:01:02.88Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/ef/e080e8d67c270ea320956bb911a9359664fc46d3b87d1f029decd33e5c4c/google_genai-1.47.0-py3-none-any.whl", hash = "sha256:e3851237556cbdec96007d8028b4b1f2425cdc5c099a8dc36b72a57e42821b60", size = 241506, upload-time = "2025-10-29T22:01:00.982Z" }, -] - -[[package]] -name = "google-pasta" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/4a/0bd53b36ff0323d10d5f24ebd67af2de10a1117f5cf4d7add90df92756f1/google-pasta-0.2.0.tar.gz", hash = "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e", size = 40430, upload-time = "2020-03-13T18:57:50.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/de/c648ef6835192e6e2cc03f40b19eeda4382c49b5bafb43d88b931c4c74ac/google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed", size = 57471, upload-time = "2020-03-13T18:57:48.872Z" }, -] - -[[package]] -name = "google-resumable-media" -version = "2.7.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-crc32c" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/5a/0efdc02665dca14e0837b62c8a1a93132c264bd02054a15abb2218afe0ae/google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0", size = 2163099, upload-time = "2024-08-07T22:20:38.555Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/35/b8d3baf8c46695858cb9d8835a53baa1eeb9906ddaf2f728a5f5b640fd1e/google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa", size = 81251, upload-time = "2024-08-07T22:20:36.409Z" }, -] - -[[package]] -name = "googleapis-common-protos" -version = "1.71.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/30/43/b25abe02db2911397819003029bef768f68a974f2ece483e6084d1a5f754/googleapis_common_protos-1.71.0.tar.gz", hash = "sha256:1aec01e574e29da63c80ba9f7bbf1ccfaacf1da877f23609fe236ca7c72a2e2e", size = 146454, upload-time = "2025-10-20T14:58:08.732Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/e8/eba9fece11d57a71e3e22ea672742c8f3cf23b35730c9e96db768b295216/googleapis_common_protos-1.71.0-py3-none-any.whl", hash = "sha256:59034a1d849dc4d18971997a72ac56246570afdd17f9369a0ff68218d50ab78c", size = 294576, upload-time = "2025-10-20T14:56:21.295Z" }, -] - -[package.optional-dependencies] -grpc = [ - { name = "grpcio" }, -] - -[[package]] -name = "greenlet" -version = "3.2.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" }, - { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646, upload-time = "2025-08-07T13:45:26.523Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519, upload-time = "2025-08-07T13:53:13.928Z" }, - { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707, upload-time = "2025-08-07T13:18:27.146Z" }, - { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" }, - { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" }, - { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" }, - { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385, upload-time = "2025-11-04T12:42:11.067Z" }, - { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329, upload-time = "2025-11-04T12:42:12.928Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" }, -] - -[[package]] -name = "grpc-google-iam-v1" -version = "0.14.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "googleapis-common-protos", extra = ["grpc"] }, - { name = "grpcio" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/1e/1011451679a983f2f5c6771a1682542ecb027776762ad031fd0d7129164b/grpc_google_iam_v1-0.14.3.tar.gz", hash = "sha256:879ac4ef33136c5491a6300e27575a9ec760f6cdf9a2518798c1b8977a5dc389", size = 23745, upload-time = "2025-10-15T21:14:53.318Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/bd/330a1bbdb1afe0b96311249e699b6dc9cfc17916394fd4503ac5aca2514b/grpc_google_iam_v1-0.14.3-py3-none-any.whl", hash = "sha256:7a7f697e017a067206a3dfef44e4c634a34d3dee135fe7d7a4613fe3e59217e6", size = 32690, upload-time = "2025-10-15T21:14:51.72Z" }, -] - -[[package]] -name = "grpc-interceptor" -version = "0.15.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "grpcio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/28/57449d5567adf4c1d3e216aaca545913fbc21a915f2da6790d6734aac76e/grpc-interceptor-0.15.4.tar.gz", hash = "sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926", size = 19322, upload-time = "2023-11-16T02:05:42.459Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/ac/8d53f230a7443401ce81791ec50a3b0e54924bf615ad287654fa4a2f5cdc/grpc_interceptor-0.15.4-py3-none-any.whl", hash = "sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d", size = 20848, upload-time = "2023-11-16T02:05:40.913Z" }, -] - -[[package]] -name = "grpcio" -version = "1.76.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b6/e0/318c1ce3ae5a17894d5791e87aea147587c9e702f24122cc7a5c8bbaeeb1/grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73", size = 12785182, upload-time = "2025-10-21T16:23:12.106Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/00/8163a1beeb6971f66b4bbe6ac9457b97948beba8dd2fc8e1281dce7f79ec/grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a", size = 5843567, upload-time = "2025-10-21T16:20:52.829Z" }, - { url = "https://files.pythonhosted.org/packages/10/c1/934202f5cf335e6d852530ce14ddb0fef21be612ba9ecbbcbd4d748ca32d/grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c", size = 11848017, upload-time = "2025-10-21T16:20:56.705Z" }, - { url = "https://files.pythonhosted.org/packages/11/0b/8dec16b1863d74af6eb3543928600ec2195af49ca58b16334972f6775663/grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465", size = 6412027, upload-time = "2025-10-21T16:20:59.3Z" }, - { url = "https://files.pythonhosted.org/packages/d7/64/7b9e6e7ab910bea9d46f2c090380bab274a0b91fb0a2fe9b0cd399fffa12/grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48", size = 7075913, upload-time = "2025-10-21T16:21:01.645Z" }, - { url = "https://files.pythonhosted.org/packages/68/86/093c46e9546073cefa789bd76d44c5cb2abc824ca62af0c18be590ff13ba/grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da", size = 6615417, upload-time = "2025-10-21T16:21:03.844Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b6/5709a3a68500a9c03da6fb71740dcdd5ef245e39266461a03f31a57036d8/grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397", size = 7199683, upload-time = "2025-10-21T16:21:06.195Z" }, - { url = "https://files.pythonhosted.org/packages/91/d3/4b1f2bf16ed52ce0b508161df3a2d186e4935379a159a834cb4a7d687429/grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749", size = 8163109, upload-time = "2025-10-21T16:21:08.498Z" }, - { url = "https://files.pythonhosted.org/packages/5c/61/d9043f95f5f4cf085ac5dd6137b469d41befb04bd80280952ffa2a4c3f12/grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00", size = 7626676, upload-time = "2025-10-21T16:21:10.693Z" }, - { url = "https://files.pythonhosted.org/packages/36/95/fd9a5152ca02d8881e4dd419cdd790e11805979f499a2e5b96488b85cf27/grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054", size = 3997688, upload-time = "2025-10-21T16:21:12.746Z" }, - { url = "https://files.pythonhosted.org/packages/60/9c/5c359c8d4c9176cfa3c61ecd4efe5affe1f38d9bae81e81ac7186b4c9cc8/grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d", size = 4709315, upload-time = "2025-10-21T16:21:15.26Z" }, -] - -[[package]] -name = "grpcio-status" -version = "1.62.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/013ef01c5a1c2fd0932c27c904934162f69f41ca0f28396d3ffe4d386123/grpcio-status-1.62.3.tar.gz", hash = "sha256:289bdd7b2459794a12cf95dc0cb727bd4a1742c37bd823f760236c937e53a485", size = 13063, upload-time = "2024-08-06T00:37:08.003Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/40/972271de05f9315c0d69f9f7ebbcadd83bc85322f538637d11bb8c67803d/grpcio_status-1.62.3-py3-none-any.whl", hash = "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8", size = 14448, upload-time = "2024-08-06T00:30:15.702Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "h5py" -version = "3.15.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4d/6a/0d79de0b025aa85dc8864de8e97659c94cf3d23148394a954dc5ca52f8c8/h5py-3.15.1.tar.gz", hash = "sha256:c86e3ed45c4473564de55aa83b6fc9e5ead86578773dfbd93047380042e26b69", size = 426236, upload-time = "2025-10-16T10:35:27.404Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/fd/8349b48b15b47768042cff06ad6e1c229f0a4bd89225bf6b6894fea27e6d/h5py-3.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5aaa330bcbf2830150c50897ea5dcbed30b5b6d56897289846ac5b9e529ec243", size = 3434135, upload-time = "2025-10-16T10:33:47.954Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b0/1c628e26a0b95858f54aba17e1599e7f6cd241727596cc2580b72cb0a9bf/h5py-3.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c970fb80001fffabb0109eaf95116c8e7c0d3ca2de854e0901e8a04c1f098509", size = 2870958, upload-time = "2025-10-16T10:33:50.907Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e3/c255cafc9b85e6ea04e2ad1bba1416baa1d7f57fc98a214be1144087690c/h5py-3.15.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80e5bb5b9508d5d9da09f81fd00abbb3f85da8143e56b1585d59bc8ceb1dba8b", size = 4504770, upload-time = "2025-10-16T10:33:54.357Z" }, - { url = "https://files.pythonhosted.org/packages/8b/23/4ab1108e87851ccc69694b03b817d92e142966a6c4abd99e17db77f2c066/h5py-3.15.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b849ba619a066196169763c33f9f0f02e381156d61c03e000bb0100f9950faf", size = 4700329, upload-time = "2025-10-16T10:33:57.616Z" }, - { url = "https://files.pythonhosted.org/packages/a4/e4/932a3a8516e4e475b90969bf250b1924dbe3612a02b897e426613aed68f4/h5py-3.15.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e7f6c841efd4e6e5b7e82222eaf90819927b6d256ab0f3aca29675601f654f3c", size = 4152456, upload-time = "2025-10-16T10:34:00.843Z" }, - { url = "https://files.pythonhosted.org/packages/2a/0a/f74d589883b13737021b2049ac796328f188dbb60c2ed35b101f5b95a3fc/h5py-3.15.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ca8a3a22458956ee7b40d8e39c9a9dc01f82933e4c030c964f8b875592f4d831", size = 4617295, upload-time = "2025-10-16T10:34:04.154Z" }, - { url = "https://files.pythonhosted.org/packages/23/95/499b4e56452ef8b6c95a271af0dde08dac4ddb70515a75f346d4f400579b/h5py-3.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:550e51131376889656feec4aff2170efc054a7fe79eb1da3bb92e1625d1ac878", size = 2882129, upload-time = "2025-10-16T10:34:06.886Z" }, - { url = "https://files.pythonhosted.org/packages/ce/bb/cfcc70b8a42222ba3ad4478bcef1791181ea908e2adbd7d53c66395edad5/h5py-3.15.1-cp311-cp311-win_arm64.whl", hash = "sha256:b39239947cb36a819147fc19e86b618dcb0953d1cd969f5ed71fc0de60392427", size = 2477121, upload-time = "2025-10-16T10:34:09.579Z" }, -] - -[[package]] -name = "hdfs" -version = "2.7.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docopt" }, - { name = "requests" }, - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/29/c7/1be559eb10cb7cac0d26373f18656c8037553619ddd4098e50b04ea8b4ab/hdfs-2.7.3.tar.gz", hash = "sha256:752a21e43f82197dce43697c73f454ba490838108c73a57a9247efb66d1c0479", size = 43540, upload-time = "2023-10-13T00:06:06.144Z" } - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httplib2" -version = "0.22.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyparsing" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/ad/2371116b22d616c194aa25ec410c9c6c37f23599dcd590502b74db197584/httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81", size = 351116, upload-time = "2023-03-21T22:29:37.214Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/6c/d2fbdaaa5959339d53ba38e94c123e4e84b8fbc4b84beb0e70d7c1608486/httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc", size = 96854, upload-time = "2023-03-21T22:29:35.683Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "hydra-core" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "antlr4-python3-runtime" }, - { name = "omegaconf" }, - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/8e/07e42bc434a847154083b315779b0a81d567154504624e181caf2c71cd98/hydra-core-1.3.2.tar.gz", hash = "sha256:8a878ed67216997c3e9d88a8e72e7b4767e81af37afb4ea3334b269a4390a824", size = 3263494, upload-time = "2023-02-23T18:33:43.03Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/50/e0edd38dcd63fb26a8547f13d28f7a008bc4a3fd4eb4ff030673f22ad41a/hydra_core-1.3.2-py3-none-any.whl", hash = "sha256:fa0238a9e31df3373b35b0bfb672c34cc92718d21f81311d8996a16de1141d8b", size = 154547, upload-time = "2023-02-23T18:33:40.801Z" }, -] - -[[package]] -name = "identify" -version = "2.6.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, -] - -[[package]] -name = "idna" -version = "3.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, -] - -[[package]] -name = "imagesize" -version = "1.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, -] - -[[package]] -name = "importlib-metadata" -version = "8.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, -] - -[[package]] -name = "iopath" -version = "0.1.10" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "portalocker", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tqdm", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/73/b3d451dfc523756cf177d3ebb0af76dc7751b341c60e2a21871be400ae29/iopath-0.1.10.tar.gz", hash = "sha256:3311c16a4d9137223e20f141655759933e1eda24f8bff166af834af3c645ef01", size = 42226, upload-time = "2022-07-09T19:00:50.866Z" } - -[[package]] -name = "ipykernel" -version = "7.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "comm" }, - { name = "debugpy" }, - { name = "ipython" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "matplotlib-inline" }, - { name = "nest-asyncio" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, -] - -[[package]] -name = "ipython" -version = "9.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "decorator" }, - { name = "ipython-pygments-lexers" }, - { name = "jedi" }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "(sys_platform != 'emscripten' and sys_platform != 'win32') or (sys_platform == 'emscripten' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform == 'win32' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/34/29b18c62e39ee2f7a6a3bba7efd952729d8aadd45ca17efc34453b717665/ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731", size = 4396932, upload-time = "2025-09-29T10:55:53.948Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/c5/d5e07995077e48220269c28a221e168c91123ad5ceee44d548f54a057fc0/ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196", size = 616170, upload-time = "2025-09-29T10:55:47.676Z" }, -] - -[[package]] -name = "ipython-pygments-lexers" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, -] - -[[package]] -name = "jedi" -version = "0.19.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parso" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "joblib" -version = "1.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, -] - -[[package]] -name = "js2py" -version = "0.74" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyjsparser" }, - { name = "six" }, - { name = "tzlocal" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cb/a5/3d8b3e4511cc21479f78f359b1b21f1fb7c640988765ffd09e55c6605e3b/Js2Py-0.74.tar.gz", hash = "sha256:39f3a6aa8469180efba3c8677271df27c31332fd1b471df1af2af58b87b8972f", size = 2504984, upload-time = "2022-11-06T10:43:53.746Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/58/2feb430d47c9f18f331494b429697342722b51f28dad8ad92a511c0f6fc8/Js2Py-0.74-py3-none-any.whl", hash = "sha256:40a508a79e2f8d624e3f2e604f90a1e6f46ac75b416d7f4745939ff4a2e95e09", size = 1033007, upload-time = "2022-11-06T10:43:50.988Z" }, -] - -[[package]] -name = "jsonpickle" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/d9/05365407d3312653498001adcebe64a14024f7189691b728610209991c46/jsonpickle-3.4.2.tar.gz", hash = "sha256:2efa2778859b6397d5804b0a98d52cd2a7d9a70fcb873bc5a3ca5acca8f499ba", size = 314339, upload-time = "2024-11-06T07:48:25.479Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/a3/e610ae0feba3e7374da08ab6cc9bb76c8bfa84b4e502aa357bda0ef6dcae/jsonpickle-3.4.2-py3-none-any.whl", hash = "sha256:fd6c273278a02b3b66e3405db3dd2f4dbc8f4a4a3123bfcab3045177c6feb9c3", size = 46256, upload-time = "2024-11-06T07:48:22.923Z" }, -] - -[[package]] -name = "jsonschema" -version = "4.25.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing" }, - { name = "rpds-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, -] - -[[package]] -name = "jsonschema-specifications" -version = "2025.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "referencing" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, -] - -[[package]] -name = "jupyter-cache" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "click" }, - { name = "importlib-metadata" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "pyyaml" }, - { name = "sqlalchemy" }, - { name = "tabulate" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bb/f7/3627358075f183956e8c4974603232b03afd4ddc7baf72c2bc9fff522291/jupyter_cache-1.0.1.tar.gz", hash = "sha256:16e808eb19e3fb67a223db906e131ea6e01f03aa27f49a7214ce6a5fec186fb9", size = 32048, upload-time = "2024-11-15T16:03:55.322Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl", hash = "sha256:9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6", size = 33907, upload-time = "2024-11-15T16:03:54.021Z" }, -] - -[[package]] -name = "jupyter-client" -version = "8.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-core" }, - { name = "python-dateutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, -] - -[[package]] -name = "jupyter-core" -version = "5.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "platformdirs" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, -] - -[[package]] -name = "jupyterlab-pygments" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, -] - -[[package]] -name = "keras" -version = "3.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "h5py" }, - { name = "ml-dtypes" }, - { name = "namex" }, - { name = "numpy" }, - { name = "optree" }, - { name = "packaging" }, - { name = "rich" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/b8/8df141314a64a31d3a21762658826f716cdf4c261c7fcdb3f729958def55/keras-3.12.0.tar.gz", hash = "sha256:536e3f8385a05ae04e82e08715a1a59988578087e187b04cb0a6fad11743f07f", size = 1129187, upload-time = "2025-10-27T20:23:11.574Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/61/cc8be27bd65082440754be443b17b6f7c185dec5e00dfdaeab4f8662e4a8/keras-3.12.0-py3-none-any.whl", hash = "sha256:02b69e007d5df8042286c3bcc2a888539e3e487590ffb08f6be1b4354df50aa8", size = 1474424, upload-time = "2025-10-27T20:23:09.571Z" }, -] - -[[package]] -name = "kfp" -version = "2.13.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "docstring-parser" }, - { name = "google-api-core" }, - { name = "google-auth" }, - { name = "google-cloud-storage" }, - { name = "kfp-pipeline-spec" }, - { name = "kfp-server-api" }, - { name = "kubernetes" }, - { name = "protobuf" }, - { name = "pyyaml" }, - { name = "requests-toolbelt" }, - { name = "tabulate" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/8e/cc5418e615c6923914911b43971c04509bf06153b6113e9e64ecdcc9e8c3/kfp-2.13.0.tar.gz", hash = "sha256:bd3e820452157472614217849f7a1cfd9c5d0d3cc7473ace80b6494ca06e8886", size = 269066, upload-time = "2025-04-28T20:55:18.863Z" } - -[[package]] -name = "kfp-pipeline-spec" -version = "0.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/21/c4/5a42b32bddae9884b0ab23135f39e49ddb510b56ba9990757c6f873b87ae/kfp_pipeline_spec-0.6.0-py3-none-any.whl", hash = "sha256:9e319b62eaa54c6790a96f796d34f071458c9cae9585c662629eb090688555a7", size = 9081, upload-time = "2024-12-06T19:48:34.321Z" }, -] - -[[package]] -name = "kfp-server-api" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "python-dateutil" }, - { name = "six" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/5c/10c7cd96cee27da45a1b90d2a95f7ec76876673fdcb0c391110ec7e75089/kfp_server_api-2.4.0.tar.gz", hash = "sha256:9d71ce49fc6757af14b052cc47e4cb531cb4e4584c2ea76ec02b9197ee9a674f", size = 83953, upload-time = "2025-02-28T00:30:13.583Z" } - -[[package]] -name = "kiwisolver" -version = "1.4.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167, upload-time = "2025-08-10T21:25:53.403Z" }, - { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579, upload-time = "2025-08-10T21:25:54.79Z" }, - { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309, upload-time = "2025-08-10T21:25:55.76Z" }, - { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596, upload-time = "2025-08-10T21:25:56.861Z" }, - { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548, upload-time = "2025-08-10T21:25:58.246Z" }, - { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618, upload-time = "2025-08-10T21:25:59.857Z" }, - { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437, upload-time = "2025-08-10T21:26:01.105Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742, upload-time = "2025-08-10T21:26:02.675Z" }, - { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810, upload-time = "2025-08-10T21:26:04.009Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579, upload-time = "2025-08-10T21:26:05.317Z" }, - { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071, upload-time = "2025-08-10T21:26:06.686Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840, upload-time = "2025-08-10T21:26:07.94Z" }, - { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159, upload-time = "2025-08-10T21:26:09.048Z" }, - { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104, upload-time = "2025-08-10T21:27:43.287Z" }, - { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592, upload-time = "2025-08-10T21:27:44.314Z" }, - { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281, upload-time = "2025-08-10T21:27:45.369Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009, upload-time = "2025-08-10T21:27:46.376Z" }, - { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929, upload-time = "2025-08-10T21:27:48.236Z" }, -] - -[[package]] -name = "kubernetes" -version = "30.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "google-auth" }, - { name = "oauthlib" }, - { name = "python-dateutil" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "requests-oauthlib" }, - { name = "six" }, - { name = "urllib3" }, - { name = "websocket-client" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/82/3c/9f29f6cab7f35df8e54f019e5719465fa97b877be2454e99f989270b4f34/kubernetes-30.1.0.tar.gz", hash = "sha256:41e4c77af9f28e7a6c314e3bd06a8c6229ddd787cad684e0ab9f69b498e98ebc", size = 887810, upload-time = "2024-06-06T15:58:30.031Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/2027ddede72d33be2effc087580aeba07e733a7360780ae87226f1f91bd8/kubernetes-30.1.0-py2.py3-none-any.whl", hash = "sha256:e212e8b7579031dd2e512168b617373bc1e03888d41ac4e04039240a292d478d", size = 1706042, upload-time = "2024-06-06T15:58:27.13Z" }, -] - -[[package]] -name = "libclang" -version = "18.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6e/5c/ca35e19a4f142adffa27e3d652196b7362fa612243e2b916845d801454fc/libclang-18.1.1.tar.gz", hash = "sha256:a1214966d08d73d971287fc3ead8dfaf82eb07fb197680d8b3859dbbbbf78250", size = 39612, upload-time = "2024-03-17T16:04:37.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/49/f5e3e7e1419872b69f6f5e82ba56e33955a74bd537d8a1f5f1eff2f3668a/libclang-18.1.1-1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:0b2e143f0fac830156feb56f9231ff8338c20aecfe72b4ffe96f19e5a1dbb69a", size = 25836045, upload-time = "2024-06-30T17:40:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e5/fc61bbded91a8830ccce94c5294ecd6e88e496cc85f6704bf350c0634b70/libclang-18.1.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:6f14c3f194704e5d09769108f03185fce7acaf1d1ae4bbb2f30a72c2400cb7c5", size = 26502641, upload-time = "2024-03-18T15:52:26.722Z" }, - { url = "https://files.pythonhosted.org/packages/db/ed/1df62b44db2583375f6a8a5e2ca5432bbdc3edb477942b9b7c848c720055/libclang-18.1.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:83ce5045d101b669ac38e6da8e58765f12da2d3aafb3b9b98d88b286a60964d8", size = 26420207, upload-time = "2024-03-17T15:00:26.63Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fc/716c1e62e512ef1c160e7984a73a5fc7df45166f2ff3f254e71c58076f7c/libclang-18.1.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:c533091d8a3bbf7460a00cb6c1a71da93bffe148f172c7d03b1c31fbf8aa2a0b", size = 24515943, upload-time = "2024-03-17T16:03:45.942Z" }, - { url = "https://files.pythonhosted.org/packages/3c/3d/f0ac1150280d8d20d059608cf2d5ff61b7c3b7f7bcf9c0f425ab92df769a/libclang-18.1.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:54dda940a4a0491a9d1532bf071ea3ef26e6dbaf03b5000ed94dd7174e8f9592", size = 23784972, upload-time = "2024-03-17T16:12:47.677Z" }, - { url = "https://files.pythonhosted.org/packages/fe/2f/d920822c2b1ce9326a4c78c0c2b4aa3fde610c7ee9f631b600acb5376c26/libclang-18.1.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:cf4a99b05376513717ab5d82a0db832c56ccea4fd61a69dbb7bccf2dfb207dbe", size = 20259606, upload-time = "2024-03-17T16:17:42.437Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c2/de1db8c6d413597076a4259cea409b83459b2db997c003578affdd32bf66/libclang-18.1.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:69f8eb8f65c279e765ffd28aaa7e9e364c776c17618af8bff22a8df58677ff4f", size = 24921494, upload-time = "2024-03-17T16:14:20.132Z" }, - { url = "https://files.pythonhosted.org/packages/0b/2d/3f480b1e1d31eb3d6de5e3ef641954e5c67430d5ac93b7fa7e07589576c7/libclang-18.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:4dd2d3b82fab35e2bf9ca717d7b63ac990a3519c7e312f19fa8e86dcc712f7fb", size = 26415083, upload-time = "2024-03-17T16:42:21.703Z" }, - { url = "https://files.pythonhosted.org/packages/71/cf/e01dc4cc79779cd82d77888a88ae2fa424d93b445ad4f6c02bfc18335b70/libclang-18.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:3f0e1f49f04d3cd198985fea0511576b0aee16f9ff0e0f0cad7f9c57ec3c20e8", size = 22361112, upload-time = "2024-03-17T16:42:59.565Z" }, -] - -[[package]] -name = "lightning-utilities" -version = "0.15.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "setuptools", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b8/39/6fc58ca81492db047149b4b8fd385aa1bfb8c28cd7cacb0c7eb0c44d842f/lightning_utilities-0.15.2.tar.gz", hash = "sha256:cdf12f530214a63dacefd713f180d1ecf5d165338101617b4742e8f22c032e24", size = 31090, upload-time = "2025-08-06T13:57:39.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/73/3d757cb3fc16f0f9794dd289bcd0c4a031d9cf54d8137d6b984b2d02edf3/lightning_utilities-0.15.2-py3-none-any.whl", hash = "sha256:ad3ab1703775044bbf880dbf7ddaaac899396c96315f3aa1779cec9d618a9841", size = 29431, upload-time = "2025-08-06T13:57:38.046Z" }, -] - -[[package]] -name = "markdown" -version = "3.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, - { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, - { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, - { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, - { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, - { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, - { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, - { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, - { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, - { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, -] - -[[package]] -name = "matplotlib" -version = "3.10.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/e2/d2d5295be2f44c678ebaf3544ba32d20c1f9ef08c49fe47f496180e1db15/matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7", size = 34804865, upload-time = "2025-10-09T00:28:00.669Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/bc/0fb489005669127ec13f51be0c6adc074d7cf191075dab1da9fe3b7a3cfc/matplotlib-3.10.7-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:53b492410a6cd66c7a471de6c924f6ede976e963c0f3097a3b7abfadddc67d0a", size = 8257507, upload-time = "2025-10-09T00:26:19.073Z" }, - { url = "https://files.pythonhosted.org/packages/e2/6a/d42588ad895279ff6708924645b5d2ed54a7fb2dc045c8a804e955aeace1/matplotlib-3.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d9749313deb729f08207718d29c86246beb2ea3fdba753595b55901dee5d2fd6", size = 8119565, upload-time = "2025-10-09T00:26:21.023Z" }, - { url = "https://files.pythonhosted.org/packages/10/b7/4aa196155b4d846bd749cf82aa5a4c300cf55a8b5e0dfa5b722a63c0f8a0/matplotlib-3.10.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2222c7ba2cbde7fe63032769f6eb7e83ab3227f47d997a8453377709b7fe3a5a", size = 8692668, upload-time = "2025-10-09T00:26:22.967Z" }, - { url = "https://files.pythonhosted.org/packages/e6/e7/664d2b97016f46683a02d854d730cfcf54ff92c1dafa424beebef50f831d/matplotlib-3.10.7-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e91f61a064c92c307c5a9dc8c05dc9f8a68f0a3be199d9a002a0622e13f874a1", size = 9521051, upload-time = "2025-10-09T00:26:25.041Z" }, - { url = "https://files.pythonhosted.org/packages/a8/a3/37aef1404efa615f49b5758a5e0261c16dd88f389bc1861e722620e4a754/matplotlib-3.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6f1851eab59ca082c95df5a500106bad73672645625e04538b3ad0f69471ffcc", size = 9576878, upload-time = "2025-10-09T00:26:27.478Z" }, - { url = "https://files.pythonhosted.org/packages/33/cd/b145f9797126f3f809d177ca378de57c45413c5099c5990de2658760594a/matplotlib-3.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:6516ce375109c60ceec579e699524e9d504cd7578506f01150f7a6bc174a775e", size = 8115142, upload-time = "2025-10-09T00:26:29.774Z" }, - { url = "https://files.pythonhosted.org/packages/2e/39/63bca9d2b78455ed497fcf51a9c71df200a11048f48249038f06447fa947/matplotlib-3.10.7-cp311-cp311-win_arm64.whl", hash = "sha256:b172db79759f5f9bc13ef1c3ef8b9ee7b37b0247f987fbbbdaa15e4f87fd46a9", size = 7992439, upload-time = "2025-10-09T00:26:40.32Z" }, - { url = "https://files.pythonhosted.org/packages/58/8f/76d5dc21ac64a49e5498d7f0472c0781dae442dd266a67458baec38288ec/matplotlib-3.10.7-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15112bcbaef211bd663fa935ec33313b948e214454d949b723998a43357b17b0", size = 8252283, upload-time = "2025-10-09T00:27:54.739Z" }, - { url = "https://files.pythonhosted.org/packages/27/0d/9c5d4c2317feb31d819e38c9f947c942f42ebd4eb935fc6fd3518a11eaa7/matplotlib-3.10.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d2a959c640cdeecdd2ec3136e8ea0441da59bcaf58d67e9c590740addba2cb68", size = 8116733, upload-time = "2025-10-09T00:27:56.406Z" }, - { url = "https://files.pythonhosted.org/packages/9a/cc/3fe688ff1355010937713164caacf9ed443675ac48a997bab6ed23b3f7c0/matplotlib-3.10.7-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3886e47f64611046bc1db523a09dd0a0a6bed6081e6f90e13806dd1d1d1b5e91", size = 8693919, upload-time = "2025-10-09T00:27:58.41Z" }, -] - -[[package]] -name = "matplotlib-inline" -version = "0.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, -] - -[[package]] -name = "mdformat" -version = "0.7.22" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/eb/b5cbf2484411af039a3d4aeb53a5160fae25dd8c84af6a4243bc2f3fedb3/mdformat-0.7.22.tar.gz", hash = "sha256:eef84fa8f233d3162734683c2a8a6222227a229b9206872e6139658d99acb1ea", size = 34610, upload-time = "2025-01-30T18:00:51.418Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/6f/94a7344f6d634fe3563bea8b33bccedee37f2726f7807e9a58440dc91627/mdformat-0.7.22-py3-none-any.whl", hash = "sha256:61122637c9e1d9be1329054f3fa216559f0d1f722b7919b060a8c2a4ae1850e5", size = 34447, upload-time = "2025-01-30T18:00:48.708Z" }, -] - -[[package]] -name = "mdformat-tables" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdformat" }, - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/fc/995ba209096bdebdeb8893d507c7b32b7e07d9a9f2cdc2ec07529947794b/mdformat_tables-1.0.0.tar.gz", hash = "sha256:a57db1ac17c4a125da794ef45539904bb8a9592e80557d525e1f169c96daa2c8", size = 6106, upload-time = "2024-08-23T23:41:33.413Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/37/d78e37d14323da3f607cd1af7daf262cb87fe614a245c15ad03bb03a2706/mdformat_tables-1.0.0-py3-none-any.whl", hash = "sha256:94cd86126141b2adc3b04c08d1441eb1272b36c39146bab078249a41c7240a9a", size = 5104, upload-time = "2024-08-23T23:41:31.863Z" }, -] - -[[package]] -name = "mdit-py-plugins" -version = "0.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f", size = 57205, upload-time = "2025-08-11T07:25:47.597Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "mistune" -version = "3.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/02/a7fb8b21d4d55ac93cdcde9d3638da5dd0ebdd3a4fed76c7725e10b81cbe/mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164", size = 94588, upload-time = "2025-08-29T07:20:43.594Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/f0/8282d9641415e9e33df173516226b404d367a0fc55e1a60424a152913abc/mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d", size = 53481, upload-time = "2025-08-29T07:20:42.218Z" }, -] - -[[package]] -name = "ml-dtypes" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/39/7d/8d85fcba868758b3a546e6914e727abd8f29ea6918079f816975c9eecd63/ml_dtypes-0.3.2.tar.gz", hash = "sha256:533059bc5f1764fac071ef54598db358c167c51a718f68f5bb55e3dee79d2967", size = 692014, upload-time = "2024-01-03T19:21:23.615Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/a4/6aabb78f1569550fd77c74d2c1d008b502c8ce72776bd88b14ea6c182c9e/ml_dtypes-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:763697ab8a88d47443997a7cdf3aac7340049aed45f7521f6b0ec8a0594821fe", size = 389791, upload-time = "2024-01-03T19:21:02.844Z" }, - { url = "https://files.pythonhosted.org/packages/d1/ed/211bf2e1c66e4ec9b712c3be848a876185c7f0d5e94bf647b60e64ef32eb/ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b89b194e9501a92d289c1ffd411380baf5daafb9818109a4f49b0a1b6dce4462", size = 2185796, upload-time = "2024-01-03T19:21:04.291Z" }, - { url = "https://files.pythonhosted.org/packages/77/a0/d4ee9e3aca5b9101c590b58555820618e8201c2ccb7004eabb417ec046ac/ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c34f2ba9660b21fe1034b608308a01be82bbef2a92fb8199f24dc6bad0d5226", size = 2164071, upload-time = "2024-01-03T19:21:05.78Z" }, - { url = "https://files.pythonhosted.org/packages/a4/db/1784b87285588788170f87e987bfb4bda218d62a70a81ebb66c94e7f9b95/ml_dtypes-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:6604877d567a29bfe7cc02969ae0f2425260e5335505cf5e7fefc3e5465f5655", size = 127681, upload-time = "2024-01-03T19:21:07.337Z" }, -] - -[[package]] -name = "mmh3" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload-time = "2025-07-29T07:43:48.49Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/87/399567b3796e134352e11a8b973cd470c06b2ecfad5468fe580833be442b/mmh3-5.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7901c893e704ee3c65f92d39b951f8f34ccf8e8566768c58103fb10e55afb8c1", size = 56107, upload-time = "2025-07-29T07:41:57.07Z" }, - { url = "https://files.pythonhosted.org/packages/c3/09/830af30adf8678955b247d97d3d9543dd2fd95684f3cd41c0cd9d291da9f/mmh3-5.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5f5536b1cbfa72318ab3bfc8a8188b949260baed186b75f0abc75b95d8c051", size = 40635, upload-time = "2025-07-29T07:41:57.903Z" }, - { url = "https://files.pythonhosted.org/packages/07/14/eaba79eef55b40d653321765ac5e8f6c9ac38780b8a7c2a2f8df8ee0fb72/mmh3-5.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cedac4f4054b8f7859e5aed41aaa31ad03fce6851901a7fdc2af0275ac533c10", size = 40078, upload-time = "2025-07-29T07:41:58.772Z" }, - { url = "https://files.pythonhosted.org/packages/bb/26/83a0f852e763f81b2265d446b13ed6d49ee49e1fc0c47b9655977e6f3d81/mmh3-5.2.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eb756caf8975882630ce4e9fbbeb9d3401242a72528230422c9ab3a0d278e60c", size = 97262, upload-time = "2025-07-29T07:41:59.678Z" }, - { url = "https://files.pythonhosted.org/packages/00/7d/b7133b10d12239aeaebf6878d7eaf0bf7d3738c44b4aba3c564588f6d802/mmh3-5.2.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:097e13c8b8a66c5753c6968b7640faefe85d8e38992703c1f666eda6ef4c3762", size = 103118, upload-time = "2025-07-29T07:42:01.197Z" }, - { url = "https://files.pythonhosted.org/packages/7b/3e/62f0b5dce2e22fd5b7d092aba285abd7959ea2b17148641e029f2eab1ffa/mmh3-5.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7c0c7845566b9686480e6a7e9044db4afb60038d5fabd19227443f0104eeee4", size = 106072, upload-time = "2025-07-29T07:42:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/66/84/ea88bb816edfe65052c757a1c3408d65c4201ddbd769d4a287b0f1a628b2/mmh3-5.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:61ac226af521a572700f863d6ecddc6ece97220ce7174e311948ff8c8919a363", size = 112925, upload-time = "2025-07-29T07:42:03.632Z" }, - { url = "https://files.pythonhosted.org/packages/2e/13/c9b1c022807db575fe4db806f442d5b5784547e2e82cff36133e58ea31c7/mmh3-5.2.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:582f9dbeefe15c32a5fa528b79b088b599a1dfe290a4436351c6090f90ddebb8", size = 120583, upload-time = "2025-07-29T07:42:04.991Z" }, - { url = "https://files.pythonhosted.org/packages/8a/5f/0e2dfe1a38f6a78788b7eb2b23432cee24623aeabbc907fed07fc17d6935/mmh3-5.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2ebfc46b39168ab1cd44670a32ea5489bcbc74a25795c61b6d888c5c2cf654ed", size = 99127, upload-time = "2025-07-29T07:42:05.929Z" }, - { url = "https://files.pythonhosted.org/packages/77/27/aefb7d663b67e6a0c4d61a513c83e39ba2237e8e4557fa7122a742a23de5/mmh3-5.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1556e31e4bd0ac0c17eaf220be17a09c171d7396919c3794274cb3415a9d3646", size = 98544, upload-time = "2025-07-29T07:42:06.87Z" }, - { url = "https://files.pythonhosted.org/packages/ab/97/a21cc9b1a7c6e92205a1b5fa030cdf62277d177570c06a239eca7bd6dd32/mmh3-5.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81df0dae22cd0da87f1c978602750f33d17fb3d21fb0f326c89dc89834fea79b", size = 106262, upload-time = "2025-07-29T07:42:07.804Z" }, - { url = "https://files.pythonhosted.org/packages/43/18/db19ae82ea63c8922a880e1498a75342311f8aa0c581c4dd07711473b5f7/mmh3-5.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:eba01ec3bd4a49b9ac5ca2bc6a73ff5f3af53374b8556fcc2966dd2af9eb7779", size = 109824, upload-time = "2025-07-29T07:42:08.735Z" }, - { url = "https://files.pythonhosted.org/packages/9f/f5/41dcf0d1969125fc6f61d8618b107c79130b5af50b18a4651210ea52ab40/mmh3-5.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e9a011469b47b752e7d20de296bb34591cdfcbe76c99c2e863ceaa2aa61113d2", size = 97255, upload-time = "2025-07-29T07:42:09.706Z" }, - { url = "https://files.pythonhosted.org/packages/32/b3/cce9eaa0efac1f0e735bb178ef9d1d2887b4927fe0ec16609d5acd492dda/mmh3-5.2.0-cp311-cp311-win32.whl", hash = "sha256:bc44fc2b886243d7c0d8daeb37864e16f232e5b56aaec27cc781d848264cfd28", size = 40779, upload-time = "2025-07-29T07:42:10.546Z" }, - { url = "https://files.pythonhosted.org/packages/7c/e9/3fa0290122e6d5a7041b50ae500b8a9f4932478a51e48f209a3879fe0b9b/mmh3-5.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:8ebf241072cf2777a492d0e09252f8cc2b3edd07dfdb9404b9757bffeb4f2cee", size = 41549, upload-time = "2025-07-29T07:42:11.399Z" }, - { url = "https://files.pythonhosted.org/packages/3a/54/c277475b4102588e6f06b2e9095ee758dfe31a149312cdbf62d39a9f5c30/mmh3-5.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5f317a727bba0e633a12e71228bc6a4acb4f471a98b1c003163b917311ea9a9", size = 39336, upload-time = "2025-07-29T07:42:12.209Z" }, -] - -[[package]] -name = "mpmath" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, -] - -[[package]] -name = "msgpack" -version = "1.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" }, - { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" }, - { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" }, - { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" }, - { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" }, - { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" }, - { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" }, - { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" }, -] - -[[package]] -name = "multidict" -version = "6.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604, upload-time = "2025-10-06T14:48:54.277Z" }, - { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715, upload-time = "2025-10-06T14:48:55.445Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332, upload-time = "2025-10-06T14:48:56.706Z" }, - { url = "https://files.pythonhosted.org/packages/31/61/0c2d50241ada71ff61a79518db85ada85fdabfcf395d5968dae1cbda04e5/multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c", size = 245212, upload-time = "2025-10-06T14:48:58.042Z" }, - { url = "https://files.pythonhosted.org/packages/ac/e0/919666a4e4b57fff1b57f279be1c9316e6cdc5de8a8b525d76f6598fefc7/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7", size = 246671, upload-time = "2025-10-06T14:49:00.004Z" }, - { url = "https://files.pythonhosted.org/packages/a1/cc/d027d9c5a520f3321b65adea289b965e7bcbd2c34402663f482648c716ce/multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7", size = 225491, upload-time = "2025-10-06T14:49:01.393Z" }, - { url = "https://files.pythonhosted.org/packages/75/c4/bbd633980ce6155a28ff04e6a6492dd3335858394d7bb752d8b108708558/multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9", size = 257322, upload-time = "2025-10-06T14:49:02.745Z" }, - { url = "https://files.pythonhosted.org/packages/4c/6d/d622322d344f1f053eae47e033b0b3f965af01212de21b10bcf91be991fb/multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8", size = 254694, upload-time = "2025-10-06T14:49:04.15Z" }, - { url = "https://files.pythonhosted.org/packages/a8/9f/78f8761c2705d4c6d7516faed63c0ebdac569f6db1bef95e0d5218fdc146/multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd", size = 246715, upload-time = "2025-10-06T14:49:05.967Z" }, - { url = "https://files.pythonhosted.org/packages/78/59/950818e04f91b9c2b95aab3d923d9eabd01689d0dcd889563988e9ea0fd8/multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb", size = 243189, upload-time = "2025-10-06T14:49:07.37Z" }, - { url = "https://files.pythonhosted.org/packages/7a/3d/77c79e1934cad2ee74991840f8a0110966d9599b3af95964c0cd79bb905b/multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6", size = 237845, upload-time = "2025-10-06T14:49:08.759Z" }, - { url = "https://files.pythonhosted.org/packages/63/1b/834ce32a0a97a3b70f86437f685f880136677ac00d8bce0027e9fd9c2db7/multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2", size = 246374, upload-time = "2025-10-06T14:49:10.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/ef/43d1c3ba205b5dec93dc97f3fba179dfa47910fc73aaaea4f7ceb41cec2a/multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff", size = 253345, upload-time = "2025-10-06T14:49:12.331Z" }, - { url = "https://files.pythonhosted.org/packages/6b/03/eaf95bcc2d19ead522001f6a650ef32811aa9e3624ff0ad37c445c7a588c/multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b", size = 246940, upload-time = "2025-10-06T14:49:13.821Z" }, - { url = "https://files.pythonhosted.org/packages/e8/df/ec8a5fd66ea6cd6f525b1fcbb23511b033c3e9bc42b81384834ffa484a62/multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34", size = 242229, upload-time = "2025-10-06T14:49:15.603Z" }, - { url = "https://files.pythonhosted.org/packages/8a/a2/59b405d59fd39ec86d1142630e9049243015a5f5291ba49cadf3c090c541/multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff", size = 41308, upload-time = "2025-10-06T14:49:16.871Z" }, - { url = "https://files.pythonhosted.org/packages/32/0f/13228f26f8b882c34da36efa776c3b7348455ec383bab4a66390e42963ae/multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81", size = 46037, upload-time = "2025-10-06T14:49:18.457Z" }, - { url = "https://files.pythonhosted.org/packages/84/1f/68588e31b000535a3207fd3c909ebeec4fb36b52c442107499c18a896a2a/multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912", size = 43023, upload-time = "2025-10-06T14:49:19.648Z" }, - { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, -] - -[[package]] -name = "mypy" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/16/22/25fac51008f0a4b2186da0dba3039128bd75d3fab8c07acd3ea5894f95cc/mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", size = 2990299, upload-time = "2023-12-21T16:29:33.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/c4/2ce11ff9ba6c9c9e89df5049ab2325c85e60274194d6816e352926de5684/mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", size = 10795101, upload-time = "2023-12-21T16:29:27.049Z" }, - { url = "https://files.pythonhosted.org/packages/bb/b7/882110d1345847ce660c51fc83b3b590b9512ec2ea44e6cfd629a7d66146/mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", size = 9849744, upload-time = "2023-12-21T16:28:28.884Z" }, - { url = "https://files.pythonhosted.org/packages/19/c6/256f253cb3fc6b30b93a9836cf3c816a3ec09f934f7b567f693e5666d14f/mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", size = 12391778, upload-time = "2023-12-21T16:28:17.728Z" }, - { url = "https://files.pythonhosted.org/packages/66/19/e0c9373258f3e84e1e24af357e5663e6b0058bb5c307287e9d1a473a9687/mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", size = 12461242, upload-time = "2023-12-21T16:29:07.651Z" }, - { url = "https://files.pythonhosted.org/packages/a9/d7/a7ee8ca5a963b5bf55a6b4bc579df77c887e7fbc0910047b7d0f7750b048/mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", size = 9205536, upload-time = "2023-12-21T16:28:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e3/b582bff8e2fc7056a8a00ec06d2ac3509fc9595af9954099ed70e0418ac3/mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", size = 2553257, upload-time = "2023-12-21T16:28:20.857Z" }, -] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - -[[package]] -name = "mypy-protobuf" -version = "3.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, - { name = "types-protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/59/48f1df10f87cf87d0638dd38f54549e98cb43fcf7ce0ab6c159816e85f23/mypy-protobuf-3.3.0.tar.gz", hash = "sha256:24f3b0aecb06656e983f58e07c732a90577b9d7af3e1066fc2b663bbf0370248", size = 23640, upload-time = "2022-08-24T11:18:16.64Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/7b/b00434b3f508eb4bc637b83c2238cacaf1ce3cc5e540a2b76f5f99302446/mypy_protobuf-3.3.0-py3-none-any.whl", hash = "sha256:15604f6943b16c05db646903261e3b3e775cf7f7990b7c37b03d043a907b650d", size = 16001, upload-time = "2022-08-24T11:18:14.462Z" }, -] - -[[package]] -name = "myst-nb" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "importlib-metadata" }, - { name = "ipykernel" }, - { name = "ipython" }, - { name = "jupyter-cache" }, - { name = "myst-parser" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "pyyaml" }, - { name = "sphinx" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/8f/71d983ed85b1aff17db25e447a9beb67b50a9116c7cff5cde26796d1ffd0/myst_nb-1.2.0.tar.gz", hash = "sha256:af459ec753b341952182b45b0a80b4776cebf80c9ee6aaca2a3f4027b440c9de", size = 79446, upload-time = "2025-02-07T18:27:02.176Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/98/fa9dee0caf4e1f2e895d047952bf84a64eb95102df14c82c20594c0afa5f/myst_nb-1.2.0-py3-none-any.whl", hash = "sha256:0e09909877848c0cf45e1aecee97481512efa29a0c4caa37870a03bba11c56c1", size = 80303, upload-time = "2025-02-07T18:27:00.088Z" }, -] - -[[package]] -name = "myst-parser" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "jinja2" }, - { name = "markdown-it-py" }, - { name = "mdit-py-plugins" }, - { name = "pyyaml" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e8/c1/48ea47b78ade0bb0281f34c9e343e3ea0c681fbc81464dbfd134e983954f/myst_parser-2.0.0.tar.gz", hash = "sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead", size = 85800, upload-time = "2023-06-13T16:30:30.136Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/f6/6d61a023d758f488e36638076e8a4ec4447a2cdf86938cf6c60cf1c860e6/myst_parser-2.0.0-py3-none-any.whl", hash = "sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14", size = 77158, upload-time = "2023-06-13T16:30:27.697Z" }, -] - -[[package]] -name = "namex" -version = "0.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0c/c0/ee95b28f029c73f8d49d8f52edaed02a1d4a9acb8b69355737fdb1faa191/namex-0.1.0.tar.gz", hash = "sha256:117f03ccd302cc48e3f5c58a296838f6b89c83455ab8683a1e85f2a430aa4306", size = 6649, upload-time = "2025-05-26T23:17:38.918Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/bc/465daf1de06409cdd4532082806770ee0d8d7df434da79c76564d0f69741/namex-0.1.0-py3-none-any.whl", hash = "sha256:e2012a474502f1e2251267062aae3114611f07df4224b6e06334c57b0f2ce87c", size = 5905, upload-time = "2025-05-26T23:17:37.695Z" }, -] - -[[package]] -name = "nbclient" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "nbformat" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424, upload-time = "2024-12-19T10:32:27.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434, upload-time = "2024-12-19T10:32:24.139Z" }, -] - -[[package]] -name = "nbconvert" -version = "7.16.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "beautifulsoup4" }, - { name = "bleach", extra = ["css"] }, - { name = "defusedxml" }, - { name = "jinja2" }, - { name = "jupyter-core" }, - { name = "jupyterlab-pygments" }, - { name = "markupsafe" }, - { name = "mistune" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "packaging" }, - { name = "pandocfilters" }, - { name = "pygments" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, -] - -[[package]] -name = "nbformat" -version = "5.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fastjsonschema" }, - { name = "jsonschema" }, - { name = "jupyter-core" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, -] - -[[package]] -name = "nbsphinx" -version = "0.9.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "jinja2" }, - { name = "nbconvert" }, - { name = "nbformat" }, - { name = "sphinx" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/51/31/85cb6129d22c75722d1e1a8db0cdaf36ab7e1e7a59189bfa275445c8ab2d/nbsphinx-0.9.3.tar.gz", hash = "sha256:ec339c8691b688f8676104a367a4b8cf3ea01fd089dc28d24dec22d563b11562", size = 171956, upload-time = "2023-08-27T10:58:10.535Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/a0/ca4aeb2f7f2608a483459a3bb486da250a7eb23eb76c9a0af154395f0cb2/nbsphinx-0.9.3-py3-none-any.whl", hash = "sha256:6e805e9627f4a358bd5720d5cbf8bf48853989c79af557afd91a5f22e163029f", size = 31039, upload-time = "2023-08-27T10:58:08.017Z" }, -] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, -] - -[[package]] -name = "networkx" -version = "3.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, -] - -[[package]] -name = "nodeenv" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, -] - -[[package]] -name = "numpy" -version = "1.26.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/57/baae43d14fe163fa0e4c47f307b6b2511ab8d7d30177c491960504252053/numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", size = 20630554, upload-time = "2024-02-05T23:51:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/1a/2e/151484f49fd03944c4a3ad9c418ed193cfd02724e138ac8a9505d056c582/numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", size = 13997127, upload-time = "2024-02-05T23:52:15.314Z" }, - { url = "https://files.pythonhosted.org/packages/79/ae/7e5b85136806f9dadf4878bf73cf223fe5c2636818ba3ab1c585d0403164/numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", size = 14222994, upload-time = "2024-02-05T23:52:47.569Z" }, - { url = "https://files.pythonhosted.org/packages/3a/d0/edc009c27b406c4f9cbc79274d6e46d634d139075492ad055e3d68445925/numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", size = 18252005, upload-time = "2024-02-05T23:53:15.637Z" }, - { url = "https://files.pythonhosted.org/packages/09/bf/2b1aaf8f525f2923ff6cfcf134ae5e750e279ac65ebf386c75a0cf6da06a/numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", size = 13885297, upload-time = "2024-02-05T23:53:42.16Z" }, - { url = "https://files.pythonhosted.org/packages/df/a0/4e0f14d847cfc2a633a1c8621d00724f3206cfeddeb66d35698c4e2cf3d2/numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", size = 18093567, upload-time = "2024-02-05T23:54:11.696Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b7/a734c733286e10a7f1a8ad1ae8c90f2d33bf604a96548e0a4a3a6739b468/numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", size = 5968812, upload-time = "2024-02-05T23:54:26.453Z" }, - { url = "https://files.pythonhosted.org/packages/3f/6b/5610004206cf7f8e7ad91c5a85a8c71b2f2f8051a0c0c4d5916b76d6cbb2/numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", size = 15811913, upload-time = "2024-02-05T23:54:53.933Z" }, -] - -[[package]] -name = "nvidia-cublas-cu12" -version = "12.8.4.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124, upload-time = "2025-03-07T01:43:53.556Z" }, - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, - { url = "https://files.pythonhosted.org/packages/70/61/7d7b3c70186fb651d0fbd35b01dbfc8e755f69fd58f817f3d0f642df20c3/nvidia_cublas_cu12-12.8.4.1-py3-none-win_amd64.whl", hash = "sha256:47e9b82132fa8d2b4944e708049229601448aaad7e6f296f630f2d1a32de35af", size = 567544208, upload-time = "2025-03-07T01:53:30.535Z" }, -] - -[[package]] -name = "nvidia-cuda-cupti-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318, upload-time = "2025-03-07T01:40:10.421Z" }, - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, - { url = "https://files.pythonhosted.org/packages/41/bc/83f5426095d93694ae39fe1311431b5d5a9bb82e48bf0dd8e19be2765942/nvidia_cuda_cupti_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:bb479dcdf7e6d4f8b0b01b115260399bf34154a1a2e9fe11c85c517d87efd98e", size = 7015759, upload-time = "2025-03-07T01:51:11.355Z" }, -] - -[[package]] -name = "nvidia-cuda-nvrtc-cu12" -version = "12.8.93" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076, upload-time = "2025-03-07T01:41:59.817Z" }, - { url = "https://files.pythonhosted.org/packages/45/51/52a3d84baa2136cc8df15500ad731d74d3a1114d4c123e043cb608d4a32b/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:7a4b6b2904850fe78e0bd179c4b655c404d4bb799ef03ddc60804247099ae909", size = 73586838, upload-time = "2025-03-07T01:52:13.483Z" }, -] - -[[package]] -name = "nvidia-cuda-runtime-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265, upload-time = "2025-03-07T01:39:43.533Z" }, - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, - { url = "https://files.pythonhosted.org/packages/30/a5/a515b7600ad361ea14bfa13fb4d6687abf500adc270f19e89849c0590492/nvidia_cuda_runtime_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:c0c6027f01505bfed6c3b21ec546f69c687689aad5f1a377554bc6ca4aa993a8", size = 944318, upload-time = "2025-03-07T01:51:01.794Z" }, -] - -[[package]] -name = "nvidia-cudnn-cu12" -version = "9.10.2.21" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878, upload-time = "2025-06-06T21:52:51.348Z" }, - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, - { url = "https://files.pythonhosted.org/packages/3d/90/0bd6e586701b3a890fd38aa71c387dab4883d619d6e5ad912ccbd05bfd67/nvidia_cudnn_cu12-9.10.2.21-py3-none-win_amd64.whl", hash = "sha256:c6288de7d63e6cf62988f0923f96dc339cea362decb1bf5b3141883392a7d65e", size = 692992268, upload-time = "2025-06-06T21:55:18.114Z" }, -] - -[[package]] -name = "nvidia-cufft-cu12" -version = "11.3.3.83" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211, upload-time = "2025-03-07T01:44:56.873Z" }, - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, - { url = "https://files.pythonhosted.org/packages/7d/ec/ce1629f1e478bb5ccd208986b5f9e0316a78538dd6ab1d0484f012f8e2a1/nvidia_cufft_cu12-11.3.3.83-py3-none-win_amd64.whl", hash = "sha256:7a64a98ef2a7c47f905aaf8931b69a3a43f27c55530c698bb2ed7c75c0b42cb7", size = 192216559, upload-time = "2025-03-07T01:53:57.106Z" }, -] - -[[package]] -name = "nvidia-cufile-cu12" -version = "1.13.1.3" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705, upload-time = "2025-03-07T01:45:41.434Z" }, -] - -[[package]] -name = "nvidia-curand-cu12" -version = "10.3.9.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754, upload-time = "2025-03-07T01:46:10.735Z" }, - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, - { url = "https://files.pythonhosted.org/packages/b9/75/70c05b2f3ed5be3bb30b7102b6eb78e100da4bbf6944fd6725c012831cab/nvidia_curand_cu12-10.3.9.90-py3-none-win_amd64.whl", hash = "sha256:f149a8ca457277da854f89cf282d6ef43176861926c7ac85b2a0fbd237c587ec", size = 62765309, upload-time = "2025-03-07T01:54:20.478Z" }, -] - -[[package]] -name = "nvidia-cusolver-cu12" -version = "11.7.3.90" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "nvidia-cusparse-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "nvidia-nvjitlink-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841, upload-time = "2025-03-07T01:46:54.356Z" }, - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, - { url = "https://files.pythonhosted.org/packages/13/c0/76ca8551b8a84146ffa189fec81c26d04adba4bc0dbe09cd6e6fd9b7de04/nvidia_cusolver_cu12-11.7.3.90-py3-none-win_amd64.whl", hash = "sha256:4a550db115fcabc4d495eb7d39ac8b58d4ab5d8e63274d3754df1c0ad6a22d34", size = 256720438, upload-time = "2025-03-07T01:54:39.898Z" }, -] - -[[package]] -name = "nvidia-cusparse-cu12" -version = "12.5.8.93" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129, upload-time = "2025-03-07T01:47:40.407Z" }, - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, - { url = "https://files.pythonhosted.org/packages/62/07/f3b2ad63f8e3d257a599f422ae34eb565e70c41031aecefa3d18b62cabd1/nvidia_cusparse_cu12-12.5.8.93-py3-none-win_amd64.whl", hash = "sha256:9a33604331cb2cac199f2e7f5104dfbb8a5a898c367a53dfda9ff2acb6b6b4dd", size = 284937404, upload-time = "2025-03-07T01:55:07.742Z" }, -] - -[[package]] -name = "nvidia-cusparselt-cu12" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557, upload-time = "2025-02-26T00:16:54.265Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d8/a6b0d0d0c2435e9310f3e2bb0d9c9dd4c33daef86aa5f30b3681defd37ea/nvidia_cusparselt_cu12-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f67fbb5831940ec829c9117b7f33807db9f9678dc2a617fbe781cac17b4e1075", size = 271020911, upload-time = "2025-02-26T00:14:47.204Z" }, -] - -[[package]] -name = "nvidia-nccl-cu12" -version = "2.27.3" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/7b/8354b784cf73b0ba51e566b4baba3ddd44fe8288a3d39ef1e06cd5417226/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ddf1a245abc36c550870f26d537a9b6087fb2e2e3d6e0ef03374c6fd19d984f", size = 322397768, upload-time = "2025-06-03T21:57:30.234Z" }, - { url = "https://files.pythonhosted.org/packages/5c/5b/4e4fff7bad39adf89f735f2bc87248c81db71205b62bcc0d5ca5b606b3c3/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039", size = 322364134, upload-time = "2025-06-03T21:58:04.013Z" }, -] - -[[package]] -name = "nvidia-nvjitlink-cu12" -version = "12.8.93" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, - { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204, upload-time = "2025-03-07T01:49:43.612Z" }, - { url = "https://files.pythonhosted.org/packages/ed/d7/34f02dad2e30c31b10a51f6b04e025e5dd60e5f936af9045a9b858a05383/nvidia_nvjitlink_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:bd93fbeeee850917903583587f4fc3a4eafa022e34572251368238ab5e6bd67f", size = 268553710, upload-time = "2025-03-07T01:56:24.13Z" }, -] - -[[package]] -name = "nvidia-nvtx-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161, upload-time = "2025-03-07T01:42:23.922Z" }, - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, - { url = "https://files.pythonhosted.org/packages/9f/99/4c9c0c329bf9fc125008c3b54c7c94c0023518d06fc025ae36431375e1fe/nvidia_nvtx_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:619c8304aedc69f02ea82dd244541a83c3d9d40993381b3b590f1adaed3db41e", size = 56492, upload-time = "2025-03-07T01:52:24.69Z" }, -] - -[[package]] -name = "oauth2client" -version = "4.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "httplib2" }, - { name = "pyasn1" }, - { name = "pyasn1-modules" }, - { name = "rsa" }, - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a6/7b/17244b1083e8e604bf154cf9b716aecd6388acd656dd01893d0d244c94d9/oauth2client-4.1.3.tar.gz", hash = "sha256:d486741e451287f69568a4d26d70d9acd73a2bbfa275746c535b4209891cccc6", size = 155910, upload-time = "2018-09-07T21:38:18.036Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/a9/4f25a14d23f0786b64875b91784607c2277eff25d48f915e39ff0cff505a/oauth2client-4.1.3-py2.py3-none-any.whl", hash = "sha256:b8a81cc5d60e2d364f0b1b98f958dbd472887acaf1a5b05e21c28c31a2d6d3ac", size = 98206, upload-time = "2018-09-07T21:38:16.742Z" }, -] - -[[package]] -name = "oauthlib" -version = "3.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, -] - -[[package]] -name = "objsize" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/0c/4b759e274c2b11f1c44232d3bde33c5f8faf746226c7acd6b637c5b53d23/objsize-0.7.1.tar.gz", hash = "sha256:91e68d2a3031efb61b0e8cb7f995ddaeb65fe5ace9e737785e029f0932c2e619", size = 16428, upload-time = "2025-01-19T02:02:03.502Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/a7/55f8f3853a4a654d3a6fbf63e646e0b469b52c174703a10db70a1cb06c7e/objsize-0.7.1-py3-none-any.whl", hash = "sha256:634a0c134c4b1ff2c340fe29caf58bc0a16cb2ff7c556df609d04f026fdf4eca", size = 11351, upload-time = "2025-01-19T02:02:01.543Z" }, -] - -[[package]] -name = "omegaconf" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "antlr4-python3-runtime" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/09/48/6388f1bb9da707110532cb70ec4d2822858ddfb44f1cdf1233c20a80ea4b/omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7", size = 3298120, upload-time = "2022-12-08T20:59:22.753Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/94/1843518e420fa3ed6919835845df698c7e27e183cb997394e4a670973a65/omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b", size = 79500, upload-time = "2022-12-08T20:59:19.686Z" }, -] - -[[package]] -name = "opentelemetry-api" -version = "1.38.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "importlib-metadata" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/d8/0f354c375628e048bd0570645b310797299754730079853095bf000fba69/opentelemetry_api-1.38.0.tar.gz", hash = "sha256:f4c193b5e8acb0912b06ac5b16321908dd0843d75049c091487322284a3eea12", size = 65242, upload-time = "2025-10-16T08:35:50.25Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/a2/d86e01c28300bd41bab8f18afd613676e2bd63515417b77636fc1add426f/opentelemetry_api-1.38.0-py3-none-any.whl", hash = "sha256:2891b0197f47124454ab9f0cf58f3be33faca394457ac3e09daba13ff50aa582", size = 65947, upload-time = "2025-10-16T08:35:30.23Z" }, -] - -[[package]] -name = "opentelemetry-sdk" -version = "1.38.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/85/cb/f0eee1445161faf4c9af3ba7b848cc22a50a3d3e2515051ad8628c35ff80/opentelemetry_sdk-1.38.0.tar.gz", hash = "sha256:93df5d4d871ed09cb4272305be4d996236eedb232253e3ab864c8620f051cebe", size = 171942, upload-time = "2025-10-16T08:36:02.257Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/2e/e93777a95d7d9c40d270a371392b6d6f1ff170c2a3cb32d6176741b5b723/opentelemetry_sdk-1.38.0-py3-none-any.whl", hash = "sha256:1c66af6564ecc1553d72d811a01df063ff097cdc82ce188da9951f93b8d10f6b", size = 132349, upload-time = "2025-10-16T08:35:46.995Z" }, -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.59b0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/40/bc/8b9ad3802cd8ac6583a4eb7de7e5d7db004e89cb7efe7008f9c8a537ee75/opentelemetry_semantic_conventions-0.59b0.tar.gz", hash = "sha256:7a6db3f30d70202d5bf9fa4b69bc866ca6a30437287de6c510fb594878aed6b0", size = 129861, upload-time = "2025-10-16T08:36:03.346Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/7d/c88d7b15ba8fe5c6b8f93be50fc11795e9fc05386c44afaf6b76fe191f9b/opentelemetry_semantic_conventions-0.59b0-py3-none-any.whl", hash = "sha256:35d3b8833ef97d614136e253c1da9342b4c3c083bbaf29ce31d572a1c3825eed", size = 207954, upload-time = "2025-10-16T08:35:48.054Z" }, -] - -[[package]] -name = "opt-einsum" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004, upload-time = "2024-09-26T14:33:24.483Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932, upload-time = "2024-09-26T14:33:23.039Z" }, -] - -[[package]] -name = "optree" -version = "0.17.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/56/c7/0853e0c59b135dff770615d2713b547b6b3b5cde7c10995b4a5825244612/optree-0.17.0.tar.gz", hash = "sha256:5335a5ec44479920620d72324c66563bd705ab2a698605dd4b6ee67dbcad7ecd", size = 163111, upload-time = "2025-07-25T11:26:11.586Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/eb/389a7dae8b113064f53909707aea9d72372fdc2eb918c48783c443cb3438/optree-0.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09fbc0e5e42b20cab11851dffb7abe2fdf289c45d29e5be2b50b4ea93d069a9f", size = 640773, upload-time = "2025-07-25T11:24:37.25Z" }, - { url = "https://files.pythonhosted.org/packages/2b/bb/2d78b524989cabb5720e85ea366addc8589b4bbd0ce3f5ea58e370e5636a/optree-0.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:90a5864689268eda75d90abded5d474ae0a7ae2608d510626724fb78a1955948", size = 346402, upload-time = "2025-07-25T11:24:38.25Z" }, - { url = "https://files.pythonhosted.org/packages/73/5c/13a2a864b0c0b39c3c193be534a195a3ab2463c7d0443d4a76e749e3ff83/optree-0.17.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3080c564c9760711aa72d1b4d700ce1417f99ad087136f415c4eb8221169e2a3", size = 362797, upload-time = "2025-07-25T11:24:39.509Z" }, - { url = "https://files.pythonhosted.org/packages/da/f5/ff7dcb5a0108ee89c2be09aed2ebd26a7e1333d8122031aa9d9322b24ee6/optree-0.17.0-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:834a8fb358b608240b3a38706a09b43974675624485fad64c8ee641dae2eb57d", size = 419450, upload-time = "2025-07-25T11:24:40.555Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e6/48a97aefd18770b55e5ed456d8183891f325cdb6d90592e5f072ed6951f8/optree-0.17.0-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1a2bd263e6b5621d000d0f94de1f245414fd5dbce365a24b7b89b1ed0ef56cf9", size = 417557, upload-time = "2025-07-25T11:24:42.396Z" }, - { url = "https://files.pythonhosted.org/packages/c4/b1/4e280edab8a86be47ec1f9bd9ed4b685d2e15f0950ae62b613b26d12a1da/optree-0.17.0-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9b37daca4ad89339b1f5320cc61ac600dcf976adbb060769d36d5542d6ebfedf", size = 414174, upload-time = "2025-07-25T11:24:43.51Z" }, - { url = "https://files.pythonhosted.org/packages/db/3b/49a9a1986215dd342525974deeb17c260a83fee8fad147276fd710ac8718/optree-0.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a146a6917f3e28cfdc268ff1770aa696c346482dd3da681c3ff92153d94450ea", size = 402000, upload-time = "2025-07-25T11:24:44.819Z" }, - { url = "https://files.pythonhosted.org/packages/00/8d/13b79d3394b83f4b1c93daac336f0eca5cb1cd5f58e10618f2c2db779cb7/optree-0.17.0-cp311-cp311-win32.whl", hash = "sha256:6b0446803d08f6aaae84f82f03c51527f36dfa15850873fc0183792247bc0071", size = 285777, upload-time = "2025-07-25T11:24:45.976Z" }, - { url = "https://files.pythonhosted.org/packages/90/32/da5191a347e33a78c2804a0cbfaed8eecb758818efda4b4d70bfd9b9b38d/optree-0.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:e39f4f00b2967116badd9617ad6aa9845d8327fe13b6dbf5bc36d8c7b4a5ea03", size = 313761, upload-time = "2025-07-25T11:24:47.047Z" }, - { url = "https://files.pythonhosted.org/packages/e1/ea/7cae17a37a8ef67a33c354fce6f136d5f253d5afa40f68701252b1b2c2a0/optree-0.17.0-cp311-cp311-win_arm64.whl", hash = "sha256:50d4dbcbca3e379cc6b374f9b5a5626ff7ea41df8373e26c3af41d89d8a4b3d5", size = 318242, upload-time = "2025-07-25T11:24:48.708Z" }, - { url = "https://files.pythonhosted.org/packages/ca/40/afec131d9dd7a18d129190d407d97c95994f42b70c3d8ab897092d4de1d9/optree-0.17.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:bd92011cd0f2de40d28a95842819e778c476ab25c12731bfef1d1a0225554f83", size = 353955, upload-time = "2025-07-25T11:26:06.75Z" }, - { url = "https://files.pythonhosted.org/packages/69/c4/94a187ed3ca71194b9da6a276790e1703c7544c8f695ac915214ae8ce934/optree-0.17.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f87f6f39015fc82d7adeee19900d246b89911319726e93cb2dbd4d1a809899bd", size = 363728, upload-time = "2025-07-25T11:26:07.959Z" }, - { url = "https://files.pythonhosted.org/packages/cd/99/23b7a484da8dfb814107b20ef2c93ef27c04f36aeb83bd976964a5b69e06/optree-0.17.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:58b0a83a967d2ef0f343db7182f0ad074eb1166bcaea909ae33909462013f151", size = 404649, upload-time = "2025-07-25T11:26:09.463Z" }, - { url = "https://files.pythonhosted.org/packages/bc/1f/7eca6da47eadb9ff2183bc9169eadde3dda0518e9a0187b99d5926fb2994/optree-0.17.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e1ae8cbbcfaa45c57f5e51c544afa554cefbbb9fe9586c108aaf2aebfadf5899", size = 316368, upload-time = "2025-07-25T11:26:10.572Z" }, -] - -[[package]] -name = "orjson" -version = "3.11.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/1d/1ea6005fffb56715fd48f632611e163d1604e8316a5bad2288bee9a1c9eb/orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39", size = 243498, upload-time = "2025-10-24T15:48:48.101Z" }, - { url = "https://files.pythonhosted.org/packages/37/d7/ffed10c7da677f2a9da307d491b9eb1d0125b0307019c4ad3d665fd31f4f/orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d", size = 128961, upload-time = "2025-10-24T15:48:49.571Z" }, - { url = "https://files.pythonhosted.org/packages/a2/96/3e4d10a18866d1368f73c8c44b7fe37cc8a15c32f2a7620be3877d4c55a3/orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175", size = 130321, upload-time = "2025-10-24T15:48:50.713Z" }, - { url = "https://files.pythonhosted.org/packages/eb/1f/465f66e93f434f968dd74d5b623eb62c657bdba2332f5a8be9f118bb74c7/orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040", size = 129207, upload-time = "2025-10-24T15:48:52.193Z" }, - { url = "https://files.pythonhosted.org/packages/28/43/d1e94837543321c119dff277ae8e348562fe8c0fafbb648ef7cb0c67e521/orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63", size = 136323, upload-time = "2025-10-24T15:48:54.806Z" }, - { url = "https://files.pythonhosted.org/packages/bf/04/93303776c8890e422a5847dd012b4853cdd88206b8bbd3edc292c90102d1/orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9", size = 137440, upload-time = "2025-10-24T15:48:56.326Z" }, - { url = "https://files.pythonhosted.org/packages/1e/ef/75519d039e5ae6b0f34d0336854d55544ba903e21bf56c83adc51cd8bf82/orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a", size = 136680, upload-time = "2025-10-24T15:48:57.476Z" }, - { url = "https://files.pythonhosted.org/packages/b5/18/bf8581eaae0b941b44efe14fee7b7862c3382fbc9a0842132cfc7cf5ecf4/orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be", size = 136160, upload-time = "2025-10-24T15:48:59.631Z" }, - { url = "https://files.pythonhosted.org/packages/c4/35/a6d582766d351f87fc0a22ad740a641b0a8e6fc47515e8614d2e4790ae10/orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7", size = 140318, upload-time = "2025-10-24T15:49:00.834Z" }, - { url = "https://files.pythonhosted.org/packages/76/b3/5a4801803ab2e2e2d703bce1a56540d9f99a9143fbec7bf63d225044fef8/orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549", size = 406330, upload-time = "2025-10-24T15:49:02.327Z" }, - { url = "https://files.pythonhosted.org/packages/80/55/a8f682f64833e3a649f620eafefee175cbfeb9854fc5b710b90c3bca45df/orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905", size = 149580, upload-time = "2025-10-24T15:49:03.517Z" }, - { url = "https://files.pythonhosted.org/packages/ad/e4/c132fa0c67afbb3eb88274fa98df9ac1f631a675e7877037c611805a4413/orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907", size = 139846, upload-time = "2025-10-24T15:49:04.761Z" }, - { url = "https://files.pythonhosted.org/packages/54/06/dc3491489efd651fef99c5908e13951abd1aead1257c67f16135f95ce209/orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c", size = 135781, upload-time = "2025-10-24T15:49:05.969Z" }, - { url = "https://files.pythonhosted.org/packages/79/b7/5e5e8d77bd4ea02a6ac54c42c818afb01dd31961be8a574eb79f1d2cfb1e/orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a", size = 131391, upload-time = "2025-10-24T15:49:07.355Z" }, - { url = "https://files.pythonhosted.org/packages/0f/dc/9484127cc1aa213be398ed735f5f270eedcb0c0977303a6f6ddc46b60204/orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045", size = 126252, upload-time = "2025-10-24T15:49:08.869Z" }, -] - -[[package]] -name = "overrides" -version = "7.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] - -[[package]] -name = "pandas" -version = "1.5.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "python-dateutil" }, - { name = "pytz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/ee/146cab1ff6d575b54ace8a6a5994048380dc94879b0125b25e62edcb9e52/pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1", size = 5203060, upload-time = "2023-01-19T08:31:39.615Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/24/a26af514113fd5eca2d8fe41ba4f22f70dfe6afefde4a6beb6a203570935/pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc", size = 18387750, upload-time = "2023-01-19T08:29:43.119Z" }, - { url = "https://files.pythonhosted.org/packages/53/c9/d2f910dace7ef849b626980d0fd033b9cded36568949c8d560c9630ad2e0/pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d", size = 11868668, upload-time = "2023-01-19T08:29:48.733Z" }, - { url = "https://files.pythonhosted.org/packages/b0/be/1843b9aff84b98899663e7cad9f45513dfdd11d69cb5bd85c648aaf6a8d4/pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc", size = 10814036, upload-time = "2023-01-19T08:29:54.886Z" }, - { url = "https://files.pythonhosted.org/packages/63/8d/c2bd356b9d4baf1c5cf8d7e251fb4540e87083072c905430da48c2bb31eb/pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae", size = 11374218, upload-time = "2023-01-19T08:30:00.5Z" }, - { url = "https://files.pythonhosted.org/packages/56/73/3351beeb807dca69fcc3c4966bcccc51552bd01549a9b13c04ab00a43f21/pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6", size = 12017319, upload-time = "2023-01-19T08:30:06.097Z" }, - { url = "https://files.pythonhosted.org/packages/da/6d/1235da14daddaa6e47f74ba0c255358f0ce7a6ee05da8bf8eb49161aa6b5/pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003", size = 10303385, upload-time = "2023-01-19T08:30:11.148Z" }, -] - -[[package]] -name = "pandas-stubs" -version = "2.2.2.240807" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "types-pytz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1f/df/0da95bc75c76f1e012e0bc0b76da31faaf4254e94b9870f25e6311145e98/pandas_stubs-2.2.2.240807.tar.gz", hash = "sha256:64a559725a57a449f46225fbafc422520b7410bff9252b661a225b5559192a93", size = 103095, upload-time = "2024-08-07T12:30:54.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/f9/22c91632ea1b4c6165952f677bf9ad95f9ac36ffd7ef3e6450144e6d8b1a/pandas_stubs-2.2.2.240807-py3-none-any.whl", hash = "sha256:893919ad82be4275f0d07bb47a95d08bae580d3fdea308a7acfcb3f02e76186e", size = 157069, upload-time = "2024-08-07T12:30:51.868Z" }, -] - -[[package]] -name = "pandocfilters" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, -] - -[[package]] -name = "parameterized" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/49/00c0c0cc24ff4266025a53e41336b79adaa5a4ebfad214f433d623f9865e/parameterized-0.9.0.tar.gz", hash = "sha256:7fc905272cefa4f364c1a3429cbbe9c0f98b793988efb5bf90aac80f08db09b1", size = 24351, upload-time = "2023-03-27T02:01:11.592Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/2f/804f58f0b856ab3bf21617cccf5b39206e6c4c94c2cd227bde125ea6105f/parameterized-0.9.0-py2.py3-none-any.whl", hash = "sha256:4e0758e3d41bea3bbd05ec14fc2c24736723f243b28d702081aef438c9372b1b", size = 20475, upload-time = "2023-03-27T02:01:09.31Z" }, -] - -[[package]] -name = "parso" -version = "0.8.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, -] - -[[package]] -name = "pexpect" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, -] - -[[package]] -name = "pillow" -version = "12.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/5a/a2f6773b64edb921a756eb0729068acad9fc5208a53f4a349396e9436721/pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc", size = 5289798, upload-time = "2025-10-15T18:21:47.763Z" }, - { url = "https://files.pythonhosted.org/packages/2e/05/069b1f8a2e4b5a37493da6c5868531c3f77b85e716ad7a590ef87d58730d/pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257", size = 4650589, upload-time = "2025-10-15T18:21:49.515Z" }, - { url = "https://files.pythonhosted.org/packages/61/e3/2c820d6e9a36432503ead175ae294f96861b07600a7156154a086ba7111a/pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642", size = 6230472, upload-time = "2025-10-15T18:21:51.052Z" }, - { url = "https://files.pythonhosted.org/packages/4f/89/63427f51c64209c5e23d4d52071c8d0f21024d3a8a487737caaf614a5795/pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3", size = 8033887, upload-time = "2025-10-15T18:21:52.604Z" }, - { url = "https://files.pythonhosted.org/packages/f6/1b/c9711318d4901093c15840f268ad649459cd81984c9ec9887756cca049a5/pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c", size = 6343964, upload-time = "2025-10-15T18:21:54.619Z" }, - { url = "https://files.pythonhosted.org/packages/41/1e/db9470f2d030b4995083044cd8738cdd1bf773106819f6d8ba12597d5352/pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227", size = 7034756, upload-time = "2025-10-15T18:21:56.151Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b0/6177a8bdd5ee4ed87cba2de5a3cc1db55ffbbec6176784ce5bb75aa96798/pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b", size = 6458075, upload-time = "2025-10-15T18:21:57.759Z" }, - { url = "https://files.pythonhosted.org/packages/bc/5e/61537aa6fa977922c6a03253a0e727e6e4a72381a80d63ad8eec350684f2/pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e", size = 7125955, upload-time = "2025-10-15T18:21:59.372Z" }, - { url = "https://files.pythonhosted.org/packages/1f/3d/d5033539344ee3cbd9a4d69e12e63ca3a44a739eb2d4c8da350a3d38edd7/pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739", size = 6298440, upload-time = "2025-10-15T18:22:00.982Z" }, - { url = "https://files.pythonhosted.org/packages/4d/42/aaca386de5cc8bd8a0254516957c1f265e3521c91515b16e286c662854c4/pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e", size = 6999256, upload-time = "2025-10-15T18:22:02.617Z" }, - { url = "https://files.pythonhosted.org/packages/ba/f1/9197c9c2d5708b785f631a6dfbfa8eb3fb9672837cb92ae9af812c13b4ed/pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d", size = 2436025, upload-time = "2025-10-15T18:22:04.598Z" }, - { url = "https://files.pythonhosted.org/packages/1d/b3/582327e6c9f86d037b63beebe981425d6811104cb443e8193824ef1a2f27/pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8", size = 5215068, upload-time = "2025-10-15T18:23:59.594Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d6/67748211d119f3b6540baf90f92fae73ae51d5217b171b0e8b5f7e5d558f/pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a", size = 4614994, upload-time = "2025-10-15T18:24:01.669Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e1/f8281e5d844c41872b273b9f2c34a4bf64ca08905668c8ae730eedc7c9fa/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197", size = 5246639, upload-time = "2025-10-15T18:24:03.403Z" }, - { url = "https://files.pythonhosted.org/packages/94/5a/0d8ab8ffe8a102ff5df60d0de5af309015163bf710c7bb3e8311dd3b3ad0/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c", size = 6986839, upload-time = "2025-10-15T18:24:05.344Z" }, - { url = "https://files.pythonhosted.org/packages/20/2e/3434380e8110b76cd9eb00a363c484b050f949b4bbe84ba770bb8508a02c/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e", size = 5313505, upload-time = "2025-10-15T18:24:07.137Z" }, - { url = "https://files.pythonhosted.org/packages/57/ca/5a9d38900d9d74785141d6580950fe705de68af735ff6e727cb911b64740/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76", size = 5963654, upload-time = "2025-10-15T18:24:09.579Z" }, - { url = "https://files.pythonhosted.org/packages/95/7e/f896623c3c635a90537ac093c6a618ebe1a90d87206e42309cb5d98a1b9e/pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5", size = 6997850, upload-time = "2025-10-15T18:24:11.495Z" }, -] - -[[package]] -name = "pip" -version = "25.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, -] - -[[package]] -name = "platformdirs" -version = "4.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, -] - -[[package]] -name = "portalocker" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/77/65b857a69ed876e1951e88aaba60f5ce6120c33703f7cb61a3c894b8c1b6/portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac", size = 95644, upload-time = "2025-06-14T13:20:40.03Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/a6/38c8e2f318bf67d338f4d629e93b0b4b9af331f455f0390ea8ce4a099b26/portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968", size = 22424, upload-time = "2025-06-14T13:20:38.083Z" }, -] - -[[package]] -name = "pre-commit" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cfgv" }, - { name = "identify" }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/21/55/fccc69a49b66c54dcb9a7d8620131a2566db973837c6611b516a2d4e87d7/pre_commit-3.3.2.tar.gz", hash = "sha256:66e37bec2d882de1f17f88075047ef8962581f83c234ac08da21a0c58953d1f0", size = 176764, upload-time = "2023-05-17T22:37:41.385Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/30/c3d5d192b97de482b9adfa356724dfbb07e293b54d94c3b98dd2e5f24759/pre_commit-3.3.2-py2.py3-none-any.whl", hash = "sha256:8056bc52181efadf4aac792b1f4f255dfd2fb5a350ded7335d251a68561e8cb6", size = 202750, upload-time = "2023-05-17T22:37:39.397Z" }, -] - -[[package]] -name = "prompt-toolkit" -version = "3.0.52" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, -] - -[[package]] -name = "propcache" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, - { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, - { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, - { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, - { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, - { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, - { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, - { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, - { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, - { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, - { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, - { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, -] - -[[package]] -name = "proto-plus" -version = "1.26.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142, upload-time = "2025-03-10T15:54:38.843Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163, upload-time = "2025-03-10T15:54:37.335Z" }, -] - -[[package]] -name = "protobuf" -version = "4.25.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/01/34c8d2b6354906d728703cb9d546a0e534de479e25f1b581e4094c4a85cc/protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd", size = 380920, upload-time = "2025-05-28T14:22:25.153Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/ff/05f34305fe6b85bbfbecbc559d423a5985605cad5eda4f47eae9e9c9c5c5/protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0", size = 392745, upload-time = "2025-05-28T14:22:10.524Z" }, - { url = "https://files.pythonhosted.org/packages/08/35/8b8a8405c564caf4ba835b1fdf554da869954712b26d8f2a98c0e434469b/protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9", size = 413736, upload-time = "2025-05-28T14:22:13.156Z" }, - { url = "https://files.pythonhosted.org/packages/28/d7/ab27049a035b258dab43445eb6ec84a26277b16105b277cbe0a7698bdc6c/protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f", size = 394537, upload-time = "2025-05-28T14:22:14.768Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6d/a4a198b61808dd3d1ee187082ccc21499bc949d639feb948961b48be9a7e/protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7", size = 294005, upload-time = "2025-05-28T14:22:16.052Z" }, - { url = "https://files.pythonhosted.org/packages/d6/c6/c9deaa6e789b6fc41b88ccbdfe7a42d2b82663248b715f55aa77fbc00724/protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0", size = 294924, upload-time = "2025-05-28T14:22:17.105Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c1/6aece0ab5209981a70cd186f164c133fdba2f51e124ff92b73de7fd24d78/protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59", size = 156757, upload-time = "2025-05-28T14:22:24.135Z" }, -] - -[[package]] -name = "psutil" -version = "7.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/ec/7b8e6b9b1d22708138630ef34c53ab2b61032c04f16adfdbb96791c8c70c/psutil-7.1.2.tar.gz", hash = "sha256:aa225cdde1335ff9684708ee8c72650f6598d5ed2114b9a7c5802030b1785018", size = 487424, upload-time = "2025-10-25T10:46:34.931Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/89/b9f8d47ddbc52d7301fc868e8224e5f44ed3c7f55e6d0f54ecaf5dd9ff5e/psutil-7.1.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9ba5c19f2d46203ee8c152c7b01df6eec87d883cfd8ee1af2ef2727f6b0f814", size = 237244, upload-time = "2025-10-25T10:47:07.086Z" }, - { url = "https://files.pythonhosted.org/packages/c8/7a/8628c2f6b240680a67d73d8742bb9ff39b1820a693740e43096d5dcb01e5/psutil-7.1.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a486030d2fe81bec023f703d3d155f4823a10a47c36784c84f1cc7f8d39bedb", size = 238101, upload-time = "2025-10-25T10:47:09.523Z" }, - { url = "https://files.pythonhosted.org/packages/30/28/5e27f4d5a0e347f8e3cc16cd7d35533dbce086c95807f1f0e9cd77e26c10/psutil-7.1.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3efd8fc791492e7808a51cb2b94889db7578bfaea22df931424f874468e389e3", size = 258675, upload-time = "2025-10-25T10:47:11.082Z" }, - { url = "https://files.pythonhosted.org/packages/e5/5c/79cf60c9acf36d087f0db0f82066fca4a780e97e5b3a2e4c38209c03d170/psutil-7.1.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2aeb9b64f481b8eabfc633bd39e0016d4d8bbcd590d984af764d80bf0851b8a", size = 260203, upload-time = "2025-10-25T10:47:13.226Z" }, - { url = "https://files.pythonhosted.org/packages/f7/03/0a464404c51685dcb9329fdd660b1721e076ccd7b3d97dee066bcc9ffb15/psutil-7.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:8e17852114c4e7996fe9da4745c2bdef001ebbf2f260dec406290e66628bdb91", size = 246714, upload-time = "2025-10-25T10:47:15.093Z" }, - { url = "https://files.pythonhosted.org/packages/6a/32/97ca2090f2f1b45b01b6aa7ae161cfe50671de097311975ca6eea3e7aabc/psutil-7.1.2-cp37-abi3-win_arm64.whl", hash = "sha256:3e988455e61c240cc879cb62a008c2699231bf3e3d061d7fce4234463fd2abb4", size = 243742, upload-time = "2025-10-25T10:47:17.302Z" }, -] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, -] - -[[package]] -name = "pure-eval" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, -] - -[[package]] -name = "pyarrow" -version = "10.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/11/71/dd884e86aa92b2d602ee2064a485106ce5b447f8cae644f1a6f6a2e72016/pyarrow-10.0.1.tar.gz", hash = "sha256:1a14f57a5f472ce8234f2964cd5184cccaa8df7e04568c64edc33b23eb285dd5", size = 994148, upload-time = "2022-11-22T22:18:16.152Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/fe/4e2d2cd7e0d544018d7c7fee3dcee80303e16111605716592dd5333a2212/pyarrow-10.0.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:e3fe5049d2e9ca661d8e43fab6ad5a4c571af12d20a57dffc392a014caebef65", size = 24978297, upload-time = "2022-11-22T22:15:37.113Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6e/915b7dfb7cfd2efd092b9b4d6579cb5848ba1dced3543bdd963df59ee2b5/pyarrow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:254017ca43c45c5098b7f2a00e995e1f8346b0fb0be225f042838323bb55283c", size = 22924198, upload-time = "2022-11-22T22:15:43.421Z" }, - { url = "https://files.pythonhosted.org/packages/ef/87/a0849cd20c75dd832683fdad0b321e6428281f3f3053e01c588269ae5b89/pyarrow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70acca1ece4322705652f48db65145b5028f2c01c7e426c5d16a30ba5d739c24", size = 33558654, upload-time = "2022-11-22T22:15:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/81/53/385279a985567a8a909bf9365cd15fc87c26ebe7db60a7220e4eeb407c87/pyarrow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb57334f2c57979a49b7be2792c31c23430ca02d24becd0b511cbe7b6b08649", size = 35844050, upload-time = "2022-11-22T22:15:59.425Z" }, - { url = "https://files.pythonhosted.org/packages/90/69/9e0ea39bed0d281e84cc3cd4a693ebc86266b705d910af9cc939e66c5d03/pyarrow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1765a18205eb1e02ccdedb66049b0ec148c2a0cb52ed1fb3aac322dfc086a6ee", size = 20195202, upload-time = "2022-11-22T22:16:19.133Z" }, -] - -[[package]] -name = "pyarrow-hotfix" -version = "0.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d2/ed/c3e8677f7abf3981838c2af7b5ac03e3589b3ef94fcb31d575426abae904/pyarrow_hotfix-0.7.tar.gz", hash = "sha256:59399cd58bdd978b2e42816a4183a55c6472d4e33d183351b6069f11ed42661d", size = 9910, upload-time = "2025-04-25T10:17:06.247Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/c3/94ade4906a2f88bc935772f59c934013b4205e773bcb4239db114a6da136/pyarrow_hotfix-0.7-py3-none-any.whl", hash = "sha256:3236f3b5f1260f0e2ac070a55c1a7b339c4bb7267839bd2015e283234e758100", size = 7923, upload-time = "2025-04-25T10:17:05.224Z" }, -] - -[[package]] -name = "pyasn1" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, -] - -[[package]] -name = "pyasn1-modules" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, -] - -[[package]] -name = "pybind11" -version = "3.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/f0/35145a3c3baffeef55d4b8324caa33abaa8fa56ab345ecd4b2211d09163e/pybind11-3.0.4.tar.gz", hash = "sha256:3286b59c8a774b9ee650169302dd5a4eedc30a8617905a0560dd8ee44775130c", size = 589533, upload-time = "2026-04-19T03:08:15.925Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/06/c3a23c9a0263b136c519f033a58d4641e73065fefc7754e9667ec206d992/pybind11-3.0.4-py3-none-any.whl", hash = "sha256:961720ee652da51d531b7b2451a6bd2bc042b0106e6d9baa48ecb7d58034ce63", size = 314166, upload-time = "2026-04-19T03:08:14.091Z" }, -] - -[[package]] -name = "pycparser" -version = "2.23" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, -] - -[[package]] -name = "pydantic" -version = "2.12.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/1e/4f0a3233767010308f2fd6bd0814597e3f63f1dc98304a9112b8759df4ff/pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74", size = 819383, upload-time = "2025-10-17T15:04:21.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/6b/83661fa77dcefa195ad5f8cd9af3d1a7450fd57cc883ad04d65446ac2029/pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf", size = 462431, upload-time = "2025-10-17T15:04:19.346Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.41.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/18/d0944e8eaaa3efd0a91b0f1fc537d3be55ad35091b6a87638211ba691964/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5", size = 457557, upload-time = "2025-10-14T10:23:47.909Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/4c/f6cbfa1e8efacd00b846764e8484fe173d25b8dab881e277a619177f3384/pydantic_core-2.41.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:28ff11666443a1a8cf2a044d6a545ebffa8382b5f7973f22c36109205e65dc80", size = 2109062, upload-time = "2025-10-14T10:20:04.486Z" }, - { url = "https://files.pythonhosted.org/packages/21/f8/40b72d3868896bfcd410e1bd7e516e762d326201c48e5b4a06446f6cf9e8/pydantic_core-2.41.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:61760c3925d4633290292bad462e0f737b840508b4f722247d8729684f6539ae", size = 1916301, upload-time = "2025-10-14T10:20:06.857Z" }, - { url = "https://files.pythonhosted.org/packages/94/4d/d203dce8bee7faeca791671c88519969d98d3b4e8f225da5b96dad226fc8/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae547b7315d055b0de2ec3965643b0ab82ad0106a7ffd29615ee9f266a02827", size = 1968728, upload-time = "2025-10-14T10:20:08.353Z" }, - { url = "https://files.pythonhosted.org/packages/65/f5/6a66187775df87c24d526985b3a5d78d861580ca466fbd9d4d0e792fcf6c/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef9ee5471edd58d1fcce1c80ffc8783a650e3e3a193fe90d52e43bb4d87bff1f", size = 2050238, upload-time = "2025-10-14T10:20:09.766Z" }, - { url = "https://files.pythonhosted.org/packages/5e/b9/78336345de97298cf53236b2f271912ce11f32c1e59de25a374ce12f9cce/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15dd504af121caaf2c95cb90c0ebf71603c53de98305621b94da0f967e572def", size = 2249424, upload-time = "2025-10-14T10:20:11.732Z" }, - { url = "https://files.pythonhosted.org/packages/99/bb/a4584888b70ee594c3d374a71af5075a68654d6c780369df269118af7402/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a926768ea49a8af4d36abd6a8968b8790f7f76dd7cbd5a4c180db2b4ac9a3a2", size = 2366047, upload-time = "2025-10-14T10:20:13.647Z" }, - { url = "https://files.pythonhosted.org/packages/5f/8d/17fc5de9d6418e4d2ae8c675f905cdafdc59d3bf3bf9c946b7ab796a992a/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916b9b7d134bff5440098a4deb80e4cb623e68974a87883299de9124126c2a8", size = 2071163, upload-time = "2025-10-14T10:20:15.307Z" }, - { url = "https://files.pythonhosted.org/packages/54/e7/03d2c5c0b8ed37a4617430db68ec5e7dbba66358b629cd69e11b4d564367/pydantic_core-2.41.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cf90535979089df02e6f17ffd076f07237efa55b7343d98760bde8743c4b265", size = 2190585, upload-time = "2025-10-14T10:20:17.3Z" }, - { url = "https://files.pythonhosted.org/packages/be/fc/15d1c9fe5ad9266a5897d9b932b7f53d7e5cfc800573917a2c5d6eea56ec/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7533c76fa647fade2d7ec75ac5cc079ab3f34879626dae5689b27790a6cf5a5c", size = 2150109, upload-time = "2025-10-14T10:20:19.143Z" }, - { url = "https://files.pythonhosted.org/packages/26/ef/e735dd008808226c83ba56972566138665b71477ad580fa5a21f0851df48/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:37e516bca9264cbf29612539801ca3cd5d1be465f940417b002905e6ed79d38a", size = 2315078, upload-time = "2025-10-14T10:20:20.742Z" }, - { url = "https://files.pythonhosted.org/packages/90/00/806efdcf35ff2ac0f938362350cd9827b8afb116cc814b6b75cf23738c7c/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c19cb355224037c83642429b8ce261ae108e1c5fbf5c028bac63c77b0f8646e", size = 2318737, upload-time = "2025-10-14T10:20:22.306Z" }, - { url = "https://files.pythonhosted.org/packages/41/7e/6ac90673fe6cb36621a2283552897838c020db343fa86e513d3f563b196f/pydantic_core-2.41.4-cp311-cp311-win32.whl", hash = "sha256:09c2a60e55b357284b5f31f5ab275ba9f7f70b7525e18a132ec1f9160b4f1f03", size = 1974160, upload-time = "2025-10-14T10:20:23.817Z" }, - { url = "https://files.pythonhosted.org/packages/e0/9d/7c5e24ee585c1f8b6356e1d11d40ab807ffde44d2db3b7dfd6d20b09720e/pydantic_core-2.41.4-cp311-cp311-win_amd64.whl", hash = "sha256:711156b6afb5cb1cb7c14a2cc2c4a8b4c717b69046f13c6b332d8a0a8f41ca3e", size = 2021883, upload-time = "2025-10-14T10:20:25.48Z" }, - { url = "https://files.pythonhosted.org/packages/33/90/5c172357460fc28b2871eb4a0fb3843b136b429c6fa827e4b588877bf115/pydantic_core-2.41.4-cp311-cp311-win_arm64.whl", hash = "sha256:6cb9cf7e761f4f8a8589a45e49ed3c0d92d1d696a45a6feaee8c904b26efc2db", size = 1968026, upload-time = "2025-10-14T10:20:27.039Z" }, - { url = "https://files.pythonhosted.org/packages/b0/12/5ba58daa7f453454464f92b3ca7b9d7c657d8641c48e370c3ebc9a82dd78/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:a1b2cfec3879afb742a7b0bcfa53e4f22ba96571c9e54d6a3afe1052d17d843b", size = 2122139, upload-time = "2025-10-14T10:22:47.288Z" }, - { url = "https://files.pythonhosted.org/packages/21/fb/6860126a77725c3108baecd10fd3d75fec25191d6381b6eb2ac660228eac/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:d175600d975b7c244af6eb9c9041f10059f20b8bbffec9e33fdd5ee3f67cdc42", size = 1936674, upload-time = "2025-10-14T10:22:49.555Z" }, - { url = "https://files.pythonhosted.org/packages/de/be/57dcaa3ed595d81f8757e2b44a38240ac5d37628bce25fb20d02c7018776/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f184d657fa4947ae5ec9c47bd7e917730fa1cbb78195037e32dcbab50aca5ee", size = 1956398, upload-time = "2025-10-14T10:22:52.19Z" }, - { url = "https://files.pythonhosted.org/packages/2f/1d/679a344fadb9695f1a6a294d739fbd21d71fa023286daeea8c0ed49e7c2b/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed810568aeffed3edc78910af32af911c835cc39ebbfacd1f0ab5dd53028e5c", size = 2138674, upload-time = "2025-10-14T10:22:54.499Z" }, - { url = "https://files.pythonhosted.org/packages/7e/7d/138e902ed6399b866f7cfe4435d22445e16fff888a1c00560d9dc79a780f/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:491535d45cd7ad7e4a2af4a5169b0d07bebf1adfd164b0368da8aa41e19907a5", size = 2104721, upload-time = "2025-10-14T10:23:26.906Z" }, - { url = "https://files.pythonhosted.org/packages/47/13/0525623cf94627f7b53b4c2034c81edc8491cbfc7c28d5447fa318791479/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:54d86c0cada6aba4ec4c047d0e348cbad7063b87ae0f005d9f8c9ad04d4a92a2", size = 1931608, upload-time = "2025-10-14T10:23:29.306Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f9/744bc98137d6ef0a233f808bfc9b18cf94624bf30836a18d3b05d08bf418/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca1124aced216b2500dc2609eade086d718e8249cb9696660ab447d50a758bd", size = 2132986, upload-time = "2025-10-14T10:23:32.057Z" }, - { url = "https://files.pythonhosted.org/packages/17/c8/629e88920171173f6049386cc71f893dff03209a9ef32b4d2f7e7c264bcf/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c9024169becccf0cb470ada03ee578d7348c119a0d42af3dcf9eda96e3a247c", size = 2187516, upload-time = "2025-10-14T10:23:34.871Z" }, - { url = "https://files.pythonhosted.org/packages/2e/0f/4f2734688d98488782218ca61bcc118329bf5de05bb7fe3adc7dd79b0b86/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:26895a4268ae5a2849269f4991cdc97236e4b9c010e51137becf25182daac405", size = 2146146, upload-time = "2025-10-14T10:23:37.342Z" }, - { url = "https://files.pythonhosted.org/packages/ed/f2/ab385dbd94a052c62224b99cf99002eee99dbec40e10006c78575aead256/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:ca4df25762cf71308c446e33c9b1fdca2923a3f13de616e2a949f38bf21ff5a8", size = 2311296, upload-time = "2025-10-14T10:23:40.145Z" }, - { url = "https://files.pythonhosted.org/packages/fc/8e/e4f12afe1beeb9823bba5375f8f258df0cc61b056b0195fb1cf9f62a1a58/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5a28fcedd762349519276c36634e71853b4541079cab4acaaac60c4421827308", size = 2315386, upload-time = "2025-10-14T10:23:42.624Z" }, - { url = "https://files.pythonhosted.org/packages/48/f7/925f65d930802e3ea2eb4d5afa4cb8730c8dc0d2cb89a59dc4ed2fcb2d74/pydantic_core-2.41.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c173ddcd86afd2535e2b695217e82191580663a1d1928239f877f5a1649ef39f", size = 2147775, upload-time = "2025-10-14T10:23:45.406Z" }, -] - -[[package]] -name = "pydata-sphinx-theme" -version = "0.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "accessible-pygments" }, - { name = "babel" }, - { name = "beautifulsoup4" }, - { name = "docutils" }, - { name = "pygments" }, - { name = "sphinx" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/20/bb50f9de3a6de69e6abd6b087b52fa2418a0418b19597601605f855ad044/pydata_sphinx_theme-0.16.1.tar.gz", hash = "sha256:a08b7f0b7f70387219dc659bff0893a7554d5eb39b59d3b8ef37b8401b7642d7", size = 2412693, upload-time = "2024-12-17T10:53:39.537Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/0d/8ba33fa83a7dcde13eb3c1c2a0c1cc29950a048bfed6d9b0d8b6bd710b4c/pydata_sphinx_theme-0.16.1-py3-none-any.whl", hash = "sha256:225331e8ac4b32682c18fcac5a57a6f717c4e632cea5dd0e247b55155faeccde", size = 6723264, upload-time = "2024-12-17T10:53:35.645Z" }, -] - -[[package]] -name = "pydot" -version = "1.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyparsing" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/13/6e/916cdf94f9b38ae0777b254c75c3bdddee49a54cc4014aac1460a7a172b3/pydot-1.4.2.tar.gz", hash = "sha256:248081a39bcb56784deb018977e428605c1c758f10897a339fce1dd728ff007d", size = 137681, upload-time = "2021-02-15T15:43:08.87Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/76/75b1bb82e9bad3e3d656556eaa353d8cd17c4254393b08ec9786ac8ed273/pydot-1.4.2-py2.py3-none-any.whl", hash = "sha256:66c98190c65b8d2e2382a441b4c0edfdb4f4c025ef9cb9874de478fb0793a451", size = 21868, upload-time = "2021-02-15T15:43:06.74Z" }, -] - -[[package]] -name = "pyfarmhash" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/7f/256f1954343fc44641d04292e1410470337db3720bd57b510782e449d6db/pyfarmhash-0.3.2.tar.gz", hash = "sha256:4146308a0ed0b37d69003199c90fa59b155666c9deb0249b40e594cee10551ea", size = 99890, upload-time = "2021-12-31T08:23:27.642Z" } - -[[package]] -name = "pyg-lib" -version = "0.5.0+pt28cpu" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -resolution-markers = [ - "sys_platform != 'darwin'", -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.5.0%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.5.0%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "pyg-lib" -version = "0.5.0+pt28cu128" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.5.0%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.5.0%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "pygments" -version = "2.19.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, -] - -[[package]] -name = "pyjsparser" -version = "2.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/ef/c72abcfa2c6accd03e7c89c400790fc3d908c5804d50a7c4e9ceabd74d23/pyjsparser-2.7.1.tar.gz", hash = "sha256:be60da6b778cc5a5296a69d8e7d614f1f870faf94e1b1b6ac591f2ad5d729579", size = 24196, upload-time = "2019-04-21T21:56:17.708Z" } - -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, -] - -[[package]] -name = "pymongo" -version = "4.15.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/7b/a709c85dc716eb85b69f71a4bb375cf1e72758a7e872103f27551243319c/pymongo-4.15.3.tar.gz", hash = "sha256:7a981271347623b5319932796690c2d301668ac3a1965974ac9f5c3b8a22cea5", size = 2470801, upload-time = "2025-10-07T21:57:50.384Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/04/3dbc426c5868961d8308f19750243f8472f587f5f8a5029ce6953ba74b82/pymongo-4.15.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a13d8f7141294404ce46dfbabb2f2d17e9b1192456651ae831fa351f86fbeb", size = 865889, upload-time = "2025-10-07T21:56:14.165Z" }, - { url = "https://files.pythonhosted.org/packages/8c/39/7f7652f53dd0eb0c4c3420a175183da757e9c53f9a2bf3ebc589758a1b9e/pymongo-4.15.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:17d13458baf4a6a9f2e787d95adf8ec50d412accb9926a044bd1c41029c323b2", size = 866230, upload-time = "2025-10-07T21:56:15.587Z" }, - { url = "https://files.pythonhosted.org/packages/6a/0b/84e119e6bab7b19cf4fa1ebb9b4c29bf6c0e76521ed8221b44e3f94a3a37/pymongo-4.15.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fe4bcb8acfb288e238190397d4a699aeb4adb70e8545a6f4e44f99d4e8096ab1", size = 1429788, upload-time = "2025-10-07T21:56:17.362Z" }, - { url = "https://files.pythonhosted.org/packages/30/39/9905fcb99903de6ac8483114d1c85efe56bc5df735857bdfcc372cf8a3ec/pymongo-4.15.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d09d895c7f08bcbed4d2e96a00e52e9e545ae5a37b32d2dc10099b205a21fc6d", size = 1456758, upload-time = "2025-10-07T21:56:18.841Z" }, - { url = "https://files.pythonhosted.org/packages/08/58/3c3ac32b8d6ebb654083d53f58e4621cd4c7f306b3b85acef667b80acf08/pymongo-4.15.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:21c0a95a4db72562fd0805e2f76496bf432ba2e27a5651f4b9c670466260c258", size = 1514666, upload-time = "2025-10-07T21:56:20.488Z" }, - { url = "https://files.pythonhosted.org/packages/19/e2/52f41de224218dc787b7e1187a1ca1a51946dcb979ee553ec917745ccd8d/pymongo-4.15.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:89e45d7fa987f4e246cdf43ff001e3f911f73eb19ba9dabc2a6d80df5c97883b", size = 1500703, upload-time = "2025-10-07T21:56:21.874Z" }, - { url = "https://files.pythonhosted.org/packages/34/0d/a5271073339ba6fc8a5f4e3a62baaa5dd8bf35246c37b512317e2a22848e/pymongo-4.15.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1246a82fa6dd73ac2c63aa7e463752d5d1ca91e0c7a23396b78f21273befd3a7", size = 1452013, upload-time = "2025-10-07T21:56:23.526Z" }, - { url = "https://files.pythonhosted.org/packages/a0/3b/f39b721ca0db9f0820e12eeffec84eb87b7502abb13a685226c5434f9618/pymongo-4.15.3-cp311-cp311-win32.whl", hash = "sha256:9483521c03f6017336f54445652ead3145154e8d3ea06418e52cea57fee43292", size = 844461, upload-time = "2025-10-07T21:56:24.867Z" }, - { url = "https://files.pythonhosted.org/packages/12/72/e58b9df862edbf238a1d71fa32749a6eaf30a3f60289602681351c29093a/pymongo-4.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:c57dad9f289d72af1d7c47a444c4d9fa401f951cedbbcc54c7dd0c2107d6d786", size = 859200, upload-time = "2025-10-07T21:56:26.393Z" }, - { url = "https://files.pythonhosted.org/packages/81/8f/64c15df5e87de759412c3b962950561202c9b39e5cc604061e056043e163/pymongo-4.15.3-cp311-cp311-win_arm64.whl", hash = "sha256:2fd3b99520f2bb013960ac29dece1b43f2f1b6d94351ca33ba1b1211ecf79a09", size = 848372, upload-time = "2025-10-07T21:56:27.994Z" }, -] - -[[package]] -name = "pyparsing" -version = "3.2.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, -] - -[[package]] -name = "pyre-extensions" -version = "0.0.32" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-inspect", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/53/5bc2532536e921c48366ad1047c1344ccef6afa5e84053f0f6e20a453767/pyre_extensions-0.0.32.tar.gz", hash = "sha256:5396715f14ea56c4d5fd0a88c57ca7e44faa468f905909edd7de4ad90ed85e55", size = 10852, upload-time = "2024-11-22T19:26:44.152Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/7a/9812cb8be9828ab688203c5ac5f743c60652887f0c00995a6f6f19f912bd/pyre_extensions-0.0.32-py3-none-any.whl", hash = "sha256:a63ba6883ab02f4b1a9f372ed4eb4a2f4c6f3d74879aa2725186fdfcfe3e5c68", size = 12766, upload-time = "2024-11-22T19:26:42.465Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, -] - -[[package]] -name = "pytz" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, -] - -[[package]] -name = "pyvers" -version = "0.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/39/c5432f541e6ea1d616dfd6ef42ce02792f7eb42dd44f5ed4439dbe17a58b/pyvers-0.1.0-py3-none-any.whl", hash = "sha256:065249805ae537ddf9a2d1a8dffc6d0a12474a347d2eaa2f35ebdae92c0c8199", size = 10092, upload-time = "2025-06-08T23:46:46.219Z" }, -] - -[[package]] -name = "pywin32" -version = "311" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, - { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, - { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, -] - -[[package]] -name = "pyzmq" -version = "27.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "implementation_name == 'pypy' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, - { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, - { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038, upload-time = "2025-09-08T23:07:51.234Z" }, - { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531, upload-time = "2025-09-08T23:07:52.795Z" }, - { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786, upload-time = "2025-09-08T23:07:55.047Z" }, - { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220, upload-time = "2025-09-08T23:07:57.172Z" }, - { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155, upload-time = "2025-09-08T23:07:59.05Z" }, - { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428, upload-time = "2025-09-08T23:08:00.663Z" }, - { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497, upload-time = "2025-09-08T23:08:02.15Z" }, - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, - { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, - { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, - { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, - { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371, upload-time = "2025-09-08T23:09:54.563Z" }, - { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, -] - -[[package]] -name = "redis" -version = "5.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "async-timeout", marker = "python_full_version < '3.11.3' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pyjwt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6a/cf/128b1b6d7086200c9f387bd4be9b2572a30b90745ef078bd8b235042dc9f/redis-5.3.1.tar.gz", hash = "sha256:ca49577a531ea64039b5a36db3d6cd1a0c7a60c34124d46924a45b956e8cf14c", size = 4626200, upload-time = "2025-07-25T08:06:27.778Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl", hash = "sha256:dc1909bd24669cc31b5f67a039700b16ec30571096c5f1f0d9d2324bff31af97", size = 272833, upload-time = "2025-07-25T08:06:26.317Z" }, -] - -[[package]] -name = "referencing" -version = "0.37.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "rpds-py" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, -] - -[[package]] -name = "regex" -version = "2025.10.23" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/c8/1d2160d36b11fbe0a61acb7c3c81ab032d9ec8ad888ac9e0a61b85ab99dd/regex-2025.10.23.tar.gz", hash = "sha256:8cbaf8ceb88f96ae2356d01b9adf5e6306fa42fa6f7eab6b97794e37c959ac26", size = 401266, upload-time = "2025-10-21T15:58:20.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/e5/74b7cd5cd76b4171f9793042045bb1726f7856dd56e582fc3e058a7a8a5e/regex-2025.10.23-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6c531155bf9179345e85032052a1e5fe1a696a6abf9cea54b97e8baefff970fd", size = 487960, upload-time = "2025-10-21T15:54:53.253Z" }, - { url = "https://files.pythonhosted.org/packages/b9/08/854fa4b3b20471d1df1c71e831b6a1aa480281e37791e52a2df9641ec5c6/regex-2025.10.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:912e9df4e89d383681268d38ad8f5780d7cccd94ba0e9aa09ca7ab7ab4f8e7eb", size = 290425, upload-time = "2025-10-21T15:54:55.21Z" }, - { url = "https://files.pythonhosted.org/packages/ab/d3/6272b1dd3ca1271661e168762b234ad3e00dbdf4ef0c7b9b72d2d159efa7/regex-2025.10.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f375c61bfc3138b13e762fe0ae76e3bdca92497816936534a0177201666f44f", size = 288278, upload-time = "2025-10-21T15:54:56.862Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/c7b365dd9d9bc0a36e018cb96f2ffb60d2ba8deb589a712b437f67de2920/regex-2025.10.23-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e248cc9446081119128ed002a3801f8031e0c219b5d3c64d3cc627da29ac0a33", size = 793289, upload-time = "2025-10-21T15:54:58.352Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fb/b8fbe9aa16cf0c21f45ec5a6c74b4cecbf1a1c0deb7089d4a6f83a9c1caa/regex-2025.10.23-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b52bf9282fdf401e4f4e721f0f61fc4b159b1307244517789702407dd74e38ca", size = 860321, upload-time = "2025-10-21T15:54:59.813Z" }, - { url = "https://files.pythonhosted.org/packages/b0/81/bf41405c772324926a9bd8a640dedaa42da0e929241834dfce0733070437/regex-2025.10.23-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c084889ab2c59765a0d5ac602fd1c3c244f9b3fcc9a65fdc7ba6b74c5287490", size = 907011, upload-time = "2025-10-21T15:55:01.968Z" }, - { url = "https://files.pythonhosted.org/packages/a4/fb/5ad6a8b92d3f88f3797b51bb4ef47499acc2d0b53d2fbe4487a892f37a73/regex-2025.10.23-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d80e8eb79009bdb0936658c44ca06e2fbbca67792013e3818eea3f5f228971c2", size = 800312, upload-time = "2025-10-21T15:55:04.15Z" }, - { url = "https://files.pythonhosted.org/packages/42/48/b4efba0168a2b57f944205d823f8e8a3a1ae6211a34508f014ec2c712f4f/regex-2025.10.23-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6f259118ba87b814a8ec475380aee5f5ae97a75852a3507cf31d055b01b5b40", size = 782839, upload-time = "2025-10-21T15:55:05.641Z" }, - { url = "https://files.pythonhosted.org/packages/13/2a/c9efb4c6c535b0559c1fa8e431e0574d229707c9ca718600366fcfef6801/regex-2025.10.23-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9b8c72a242683dcc72d37595c4f1278dfd7642b769e46700a8df11eab19dfd82", size = 854270, upload-time = "2025-10-21T15:55:07.27Z" }, - { url = "https://files.pythonhosted.org/packages/34/2d/68eecc1bdaee020e8ba549502291c9450d90d8590d0552247c9b543ebf7b/regex-2025.10.23-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a8d7b7a0a3df9952f9965342159e0c1f05384c0f056a47ce8b61034f8cecbe83", size = 845771, upload-time = "2025-10-21T15:55:09.477Z" }, - { url = "https://files.pythonhosted.org/packages/a5/cd/a1ae499cf9b87afb47a67316bbf1037a7c681ffe447c510ed98c0aa2c01c/regex-2025.10.23-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:413bfea20a484c524858125e92b9ce6ffdd0a4b97d4ff96b5859aa119b0f1bdd", size = 788778, upload-time = "2025-10-21T15:55:11.396Z" }, - { url = "https://files.pythonhosted.org/packages/38/f9/70765e63f5ea7d43b2b6cd4ee9d3323f16267e530fb2a420d92d991cf0fc/regex-2025.10.23-cp311-cp311-win32.whl", hash = "sha256:f76deef1f1019a17dad98f408b8f7afc4bd007cbe835ae77b737e8c7f19ae575", size = 265666, upload-time = "2025-10-21T15:55:13.306Z" }, - { url = "https://files.pythonhosted.org/packages/9c/1a/18e9476ee1b63aaec3844d8e1cb21842dc19272c7e86d879bfc0dcc60db3/regex-2025.10.23-cp311-cp311-win_amd64.whl", hash = "sha256:59bba9f7125536f23fdab5deeea08da0c287a64c1d3acc1c7e99515809824de8", size = 277600, upload-time = "2025-10-21T15:55:15.087Z" }, - { url = "https://files.pythonhosted.org/packages/1d/1b/c019167b1f7a8ec77251457e3ff0339ed74ca8bce1ea13138dc98309c923/regex-2025.10.23-cp311-cp311-win_arm64.whl", hash = "sha256:b103a752b6f1632ca420225718d6ed83f6a6ced3016dd0a4ab9a6825312de566", size = 269974, upload-time = "2025-10-21T15:55:16.841Z" }, -] - -[[package]] -name = "requests" -version = "2.32.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, -] - -[[package]] -name = "requests-oauthlib" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "oauthlib" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, -] - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, -] - -[[package]] -name = "rich" -version = "14.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, -] - -[[package]] -name = "rpds-py" -version = "0.28.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/dc/95f074d43452b3ef5d06276696ece4b3b5d696e7c9ad7173c54b1390cd70/rpds_py-0.28.0.tar.gz", hash = "sha256:abd4df20485a0983e2ca334a216249b6186d6e3c1627e106651943dbdb791aea", size = 27419, upload-time = "2025-10-22T22:24:29.327Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/34/058d0db5471c6be7bef82487ad5021ff8d1d1d27794be8730aad938649cf/rpds_py-0.28.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:03065002fd2e287725d95fbc69688e0c6daf6c6314ba38bdbaa3895418e09296", size = 362344, upload-time = "2025-10-22T22:21:39.713Z" }, - { url = "https://files.pythonhosted.org/packages/5d/67/9503f0ec8c055a0782880f300c50a2b8e5e72eb1f94dfc2053da527444dd/rpds_py-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28ea02215f262b6d078daec0b45344c89e161eab9526b0d898221d96fdda5f27", size = 348440, upload-time = "2025-10-22T22:21:41.056Z" }, - { url = "https://files.pythonhosted.org/packages/68/2e/94223ee9b32332a41d75b6f94b37b4ce3e93878a556fc5f152cbd856a81f/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25dbade8fbf30bcc551cb352376c0ad64b067e4fc56f90e22ba70c3ce205988c", size = 379068, upload-time = "2025-10-22T22:21:42.593Z" }, - { url = "https://files.pythonhosted.org/packages/b4/25/54fd48f9f680cfc44e6a7f39a5fadf1d4a4a1fd0848076af4a43e79f998c/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c03002f54cc855860bfdc3442928ffdca9081e73b5b382ed0b9e8efe6e5e205", size = 390518, upload-time = "2025-10-22T22:21:43.998Z" }, - { url = "https://files.pythonhosted.org/packages/1b/85/ac258c9c27f2ccb1bd5d0697e53a82ebcf8088e3186d5d2bf8498ee7ed44/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9699fa7990368b22032baf2b2dce1f634388e4ffc03dfefaaac79f4695edc95", size = 525319, upload-time = "2025-10-22T22:21:45.645Z" }, - { url = "https://files.pythonhosted.org/packages/40/cb/c6734774789566d46775f193964b76627cd5f42ecf246d257ce84d1912ed/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b06fe1a75e05e0713f06ea0c89ecb6452210fd60e2f1b6ddc1067b990e08d9", size = 404896, upload-time = "2025-10-22T22:21:47.544Z" }, - { url = "https://files.pythonhosted.org/packages/1f/53/14e37ce83202c632c89b0691185dca9532288ff9d390eacae3d2ff771bae/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9f83e7b326a3f9ec3ef84cda98fb0a74c7159f33e692032233046e7fd15da2", size = 382862, upload-time = "2025-10-22T22:21:49.176Z" }, - { url = "https://files.pythonhosted.org/packages/6a/83/f3642483ca971a54d60caa4449f9d6d4dbb56a53e0072d0deff51b38af74/rpds_py-0.28.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:0d3259ea9ad8743a75a43eb7819324cdab393263c91be86e2d1901ee65c314e0", size = 398848, upload-time = "2025-10-22T22:21:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/44/09/2d9c8b2f88e399b4cfe86efdf2935feaf0394e4f14ab30c6c5945d60af7d/rpds_py-0.28.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a7548b345f66f6695943b4ef6afe33ccd3f1b638bd9afd0f730dd255c249c9e", size = 412030, upload-time = "2025-10-22T22:21:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/dd/f5/e1cec473d4bde6df1fd3738be8e82d64dd0600868e76e92dfeaebbc2d18f/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9a40040aa388b037eb39416710fbcce9443498d2eaab0b9b45ae988b53f5c67", size = 559700, upload-time = "2025-10-22T22:21:54.123Z" }, - { url = "https://files.pythonhosted.org/packages/8d/be/73bb241c1649edbf14e98e9e78899c2c5e52bbe47cb64811f44d2cc11808/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f60c7ea34e78c199acd0d3cda37a99be2c861dd2b8cf67399784f70c9f8e57d", size = 584581, upload-time = "2025-10-22T22:21:56.102Z" }, - { url = "https://files.pythonhosted.org/packages/9c/9c/ffc6e9218cd1eb5c2c7dbd276c87cd10e8c2232c456b554169eb363381df/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1571ae4292649100d743b26d5f9c63503bb1fedf538a8f29a98dce2d5ba6b4e6", size = 549981, upload-time = "2025-10-22T22:21:58.253Z" }, - { url = "https://files.pythonhosted.org/packages/5f/50/da8b6d33803a94df0149345ee33e5d91ed4d25fc6517de6a25587eae4133/rpds_py-0.28.0-cp311-cp311-win32.whl", hash = "sha256:5cfa9af45e7c1140af7321fa0bef25b386ee9faa8928c80dc3a5360971a29e8c", size = 214729, upload-time = "2025-10-22T22:21:59.625Z" }, - { url = "https://files.pythonhosted.org/packages/12/fd/b0f48c4c320ee24c8c20df8b44acffb7353991ddf688af01eef5f93d7018/rpds_py-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd8d86b5d29d1b74100982424ba53e56033dc47720a6de9ba0259cf81d7cecaa", size = 223977, upload-time = "2025-10-22T22:22:01.092Z" }, - { url = "https://files.pythonhosted.org/packages/b4/21/c8e77a2ac66e2ec4e21f18a04b4e9a0417ecf8e61b5eaeaa9360a91713b4/rpds_py-0.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e27d3a5709cc2b3e013bf93679a849213c79ae0573f9b894b284b55e729e120", size = 217326, upload-time = "2025-10-22T22:22:02.944Z" }, - { url = "https://files.pythonhosted.org/packages/ae/bc/b43f2ea505f28119bd551ae75f70be0c803d2dbcd37c1b3734909e40620b/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f5e7101145427087e493b9c9b959da68d357c28c562792300dd21a095118ed16", size = 363913, upload-time = "2025-10-22T22:24:07.129Z" }, - { url = "https://files.pythonhosted.org/packages/28/f2/db318195d324c89a2c57dc5195058cbadd71b20d220685c5bd1da79ee7fe/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:31eb671150b9c62409a888850aaa8e6533635704fe2b78335f9aaf7ff81eec4d", size = 350452, upload-time = "2025-10-22T22:24:08.754Z" }, - { url = "https://files.pythonhosted.org/packages/ae/f2/1391c819b8573a4898cedd6b6c5ec5bc370ce59e5d6bdcebe3c9c1db4588/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b55c1f64482f7d8bd39942f376bfdf2f6aec637ee8c805b5041e14eeb771db", size = 380957, upload-time = "2025-10-22T22:24:10.826Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5c/e5de68ee7eb7248fce93269833d1b329a196d736aefb1a7481d1e99d1222/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24743a7b372e9a76171f6b69c01aedf927e8ac3e16c474d9fe20d552a8cb45c7", size = 391919, upload-time = "2025-10-22T22:24:12.559Z" }, - { url = "https://files.pythonhosted.org/packages/fb/4f/2376336112cbfeb122fd435d608ad8d5041b3aed176f85a3cb32c262eb80/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:389c29045ee8bbb1627ea190b4976a310a295559eaf9f1464a1a6f2bf84dde78", size = 528541, upload-time = "2025-10-22T22:24:14.197Z" }, - { url = "https://files.pythonhosted.org/packages/68/53/5ae232e795853dd20da7225c5dd13a09c0a905b1a655e92bdf8d78a99fd9/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23690b5827e643150cf7b49569679ec13fe9a610a15949ed48b85eb7f98f34ec", size = 405629, upload-time = "2025-10-22T22:24:16.001Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2d/351a3b852b683ca9b6b8b38ed9efb2347596973849ba6c3a0e99877c10aa/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f0c9266c26580e7243ad0d72fc3e01d6b33866cfab5084a6da7576bcf1c4f72", size = 384123, upload-time = "2025-10-22T22:24:17.585Z" }, - { url = "https://files.pythonhosted.org/packages/e0/15/870804daa00202728cc91cb8e2385fa9f1f4eb49857c49cfce89e304eae6/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4c6c4db5d73d179746951486df97fd25e92396be07fc29ee8ff9a8f5afbdfb27", size = 400923, upload-time = "2025-10-22T22:24:19.512Z" }, - { url = "https://files.pythonhosted.org/packages/53/25/3706b83c125fa2a0bccceac951de3f76631f6bd0ee4d02a0ed780712ef1b/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3b695a8fa799dd2cfdb4804b37096c5f6dba1ac7f48a7fbf6d0485bcd060316", size = 413767, upload-time = "2025-10-22T22:24:21.316Z" }, - { url = "https://files.pythonhosted.org/packages/ef/f9/ce43dbe62767432273ed2584cef71fef8411bddfb64125d4c19128015018/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6aa1bfce3f83baf00d9c5fcdbba93a3ab79958b4c7d7d1f55e7fe68c20e63912", size = 561530, upload-time = "2025-10-22T22:24:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/46/c9/ffe77999ed8f81e30713dd38fd9ecaa161f28ec48bb80fa1cd9118399c27/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b0f9dceb221792b3ee6acb5438eb1f02b0cb2c247796a72b016dcc92c6de829", size = 585453, upload-time = "2025-10-22T22:24:24.779Z" }, - { url = "https://files.pythonhosted.org/packages/ed/d2/4a73b18821fd4669762c855fd1f4e80ceb66fb72d71162d14da58444a763/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5d0145edba8abd3db0ab22b5300c99dc152f5c9021fab861be0f0544dc3cbc5f", size = 552199, upload-time = "2025-10-22T22:24:26.54Z" }, -] - -[[package]] -name = "rsa" -version = "4.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, -] - -[[package]] -name = "ruff" -version = "0.15.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, - { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, - { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, - { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, - { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, - { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, - { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, - { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, - { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, - { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, - { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, - { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, - { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, -] - -[[package]] -name = "scikit-build-core" -version = "0.12.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "pathspec" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/cd/9ebb50029b6d8a3ee9e38cdce514ebd70190ec1edf28ab0a1f66d0b84670/scikit_build_core-0.12.2.tar.gz", hash = "sha256:562e0bbc9de1a354c87825ccf732080268d6582a0200f648e8c4a2dcb1e3736d", size = 303553, upload-time = "2026-03-05T18:25:57.666Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/49/b2f0fbe3165d55c02e7f9eec6a10685d518af0ef6e919ff2f589c2d15c85/scikit_build_core-0.12.2-py3-none-any.whl", hash = "sha256:6ea4730da400f9a998ec3287bd3ebc1d751fe45ad0a93451bead8618adbc02b1", size = 192625, upload-time = "2026-03-05T18:25:56.207Z" }, -] - -[[package]] -name = "scikit-learn" -version = "1.7.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "joblib" }, - { name = "numpy" }, - { name = "scipy" }, - { name = "threadpoolctl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967, upload-time = "2025-09-09T08:20:32.421Z" }, - { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645, upload-time = "2025-09-09T08:20:34.436Z" }, - { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424, upload-time = "2025-09-09T08:20:36.776Z" }, - { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234, upload-time = "2025-09-09T08:20:38.957Z" }, - { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244, upload-time = "2025-09-09T08:20:41.166Z" }, -] - -[[package]] -name = "scipy" -version = "1.16.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881, upload-time = "2025-10-28T17:31:47.104Z" }, - { url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012, upload-time = "2025-10-28T17:31:53.411Z" }, - { url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935, upload-time = "2025-10-28T17:31:57.361Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466, upload-time = "2025-10-28T17:32:01.875Z" }, - { url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618, upload-time = "2025-10-28T17:32:06.902Z" }, - { url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798, upload-time = "2025-10-28T17:32:12.665Z" }, - { url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154, upload-time = "2025-10-28T17:32:17.961Z" }, - { url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540, upload-time = "2025-10-28T17:32:23.907Z" }, - { url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107, upload-time = "2025-10-28T17:32:29.921Z" }, - { url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272, upload-time = "2025-10-28T17:32:34.577Z" }, -] - -[[package]] -name = "setuptools" -version = "80.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, -] - -[[package]] -name = "shapely" -version = "2.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4d/bc/0989043118a27cccb4e906a46b7565ce36ca7b57f5a18b78f4f1b0f72d9d/shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9", size = 315489, upload-time = "2025-09-24T13:51:41.432Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8d/1ff672dea9ec6a7b5d422eb6d095ed886e2e523733329f75fdcb14ee1149/shapely-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91121757b0a36c9aac3427a651a7e6567110a4a67c97edf04f8d55d4765f6618", size = 1820038, upload-time = "2025-09-24T13:50:15.628Z" }, - { url = "https://files.pythonhosted.org/packages/4f/ce/28fab8c772ce5db23a0d86bf0adaee0c4c79d5ad1db766055fa3dab442e2/shapely-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:16a9c722ba774cf50b5d4541242b4cce05aafd44a015290c82ba8a16931ff63d", size = 1626039, upload-time = "2025-09-24T13:50:16.881Z" }, - { url = "https://files.pythonhosted.org/packages/70/8b/868b7e3f4982f5006e9395c1e12343c66a8155c0374fdc07c0e6a1ab547d/shapely-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cc4f7397459b12c0b196c9efe1f9d7e92463cbba142632b4cc6d8bbbbd3e2b09", size = 3001519, upload-time = "2025-09-24T13:50:18.606Z" }, - { url = "https://files.pythonhosted.org/packages/13/02/58b0b8d9c17c93ab6340edd8b7308c0c5a5b81f94ce65705819b7416dba5/shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:136ab87b17e733e22f0961504d05e77e7be8c9b5a8184f685b4a91a84efe3c26", size = 3110842, upload-time = "2025-09-24T13:50:21.77Z" }, - { url = "https://files.pythonhosted.org/packages/af/61/8e389c97994d5f331dcffb25e2fa761aeedfb52b3ad9bcdd7b8671f4810a/shapely-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:16c5d0fc45d3aa0a69074979f4f1928ca2734fb2e0dde8af9611e134e46774e7", size = 4021316, upload-time = "2025-09-24T13:50:23.626Z" }, - { url = "https://files.pythonhosted.org/packages/d3/d4/9b2a9fe6039f9e42ccf2cb3e84f219fd8364b0c3b8e7bbc857b5fbe9c14c/shapely-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ddc759f72b5b2b0f54a7e7cde44acef680a55019eb52ac63a7af2cf17cb9cd2", size = 4178586, upload-time = "2025-09-24T13:50:25.443Z" }, - { url = "https://files.pythonhosted.org/packages/16/f6/9840f6963ed4decf76b08fd6d7fed14f8779fb7a62cb45c5617fa8ac6eab/shapely-2.1.2-cp311-cp311-win32.whl", hash = "sha256:2fa78b49485391224755a856ed3b3bd91c8455f6121fee0db0e71cefb07d0ef6", size = 1543961, upload-time = "2025-09-24T13:50:26.968Z" }, - { url = "https://files.pythonhosted.org/packages/38/1e/3f8ea46353c2a33c1669eb7327f9665103aa3a8dfe7f2e4ef714c210b2c2/shapely-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:c64d5c97b2f47e3cd9b712eaced3b061f2b71234b3fc263e0fcf7d889c6559dc", size = 1722856, upload-time = "2025-09-24T13:50:28.497Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "snowballstemmer" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, -] - -[[package]] -name = "soupsieve" -version = "2.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, -] - -[[package]] -name = "sphinx" -version = "7.4.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alabaster" }, - { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "docutils" }, - { name = "imagesize" }, - { name = "jinja2" }, - { name = "packaging" }, - { name = "pygments" }, - { name = "requests" }, - { name = "snowballstemmer" }, - { name = "sphinxcontrib-applehelp" }, - { name = "sphinxcontrib-devhelp" }, - { name = "sphinxcontrib-htmlhelp" }, - { name = "sphinxcontrib-jsmath" }, - { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-serializinghtml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911, upload-time = "2024-07-20T14:46:56.059Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624, upload-time = "2024-07-20T14:46:52.142Z" }, -] - -[[package]] -name = "sphinx-autoapi" -version = "3.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "astroid" }, - { name = "jinja2" }, - { name = "pyyaml" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/a8/22b379a2a75ccb881217d3d4ae56d7d35f2d1bb4c8c0c51d0253676746a1/sphinx_autoapi-3.6.0.tar.gz", hash = "sha256:c685f274e41d0842ae7e199460c322c4bd7fec816ccc2da8d806094b4f64af06", size = 55417, upload-time = "2025-02-18T01:50:55.241Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/17/0eda9dc80fcaf257222b506844207e71b5d59567c41bbdcca2a72da119b9/sphinx_autoapi-3.6.0-py3-none-any.whl", hash = "sha256:f3b66714493cab140b0e896d33ce7137654a16ac1edb6563edcbd47bf975f711", size = 35281, upload-time = "2025-02-18T01:50:52.789Z" }, -] - -[[package]] -name = "sphinx-autodoc-typehints" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cd/03e7b917230dc057922130a79ba0240df1693bfd76727ea33fae84b39138/sphinx_autodoc_typehints-2.3.0.tar.gz", hash = "sha256:535c78ed2d6a1bad393ba9f3dfa2602cf424e2631ee207263e07874c38fde084", size = 40709, upload-time = "2024-08-29T16:25:48.343Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/f3/e0a4ce49da4b6f4e4ce84b3c39a0677831884cb9d8a87ccbf1e9e56e53ac/sphinx_autodoc_typehints-2.3.0-py3-none-any.whl", hash = "sha256:3098e2c6d0ba99eacd013eb06861acc9b51c6e595be86ab05c08ee5506ac0c67", size = 19836, upload-time = "2024-08-29T16:25:46.707Z" }, -] - -[[package]] -name = "sphinx-copybutton" -version = "0.5.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, -] - -[[package]] -name = "sphinx-design" -version = "0.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/2b/fdcfecad13079cc5c620b9ed380dc4b29f02cff69a1189057da0909e25ef/sphinx_design-0.6.0.tar.gz", hash = "sha256:ec8e3c5c59fed4049b3a5a2e209360feab31829346b5f6a0c7c342b894082192", size = 2193531, upload-time = "2024-05-22T23:12:19.628Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/e6/b0a74746e5fe33ed541ab2b67fc94bda6a604c66e92eda0e53cd29a6eab3/sphinx_design-0.6.0-py3-none-any.whl", hash = "sha256:e9bd07eecec82eb07ff72cb50fc3624e186b04f5661270bc7b62db86c7546e95", size = 2215316, upload-time = "2024-05-22T23:12:17.223Z" }, -] - -[[package]] -name = "sphinx-hoverxref" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, - { name = "sphinxcontrib-jquery" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e0/93/180ade869c9d6a16ea58faaf4a130e3e61813baa04184fa56b6649cd5475/sphinx-hoverxref-1.3.0.tar.gz", hash = "sha256:e517dab4cb8186da58d78c53781459ee1116ec9c8413580c7dc43e124c5f3177", size = 1716338, upload-time = "2022-10-25T12:06:23.621Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/fa/1b860e4662906c7f7276a84d361b4ecdb2404adb39610b1673f82cf51b03/sphinx_hoverxref-1.3.0-py2.py3-none-any.whl", hash = "sha256:1064e4b1da49422873de555d79dc544da1556820fee05ab56f39d36cc86ba6ad", size = 32453, upload-time = "2022-10-25T12:06:19.137Z" }, -] - -[[package]] -name = "sphinx-rtd-theme" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "sphinx" }, - { name = "sphinxcontrib-jquery" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/33/2a35a9cdbfda9086bda11457bcc872173ab3565b16b6d7f6b3efaa6dc3d6/sphinx_rtd_theme-2.0.0.tar.gz", hash = "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b", size = 2785005, upload-time = "2023-11-28T04:14:03.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/46/00fda84467815c29951a9c91e3ae7503c409ddad04373e7cfc78daad4300/sphinx_rtd_theme-2.0.0-py2.py3-none-any.whl", hash = "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586", size = 2824721, upload-time = "2023-11-28T04:13:59.589Z" }, -] - -[[package]] -name = "sphinx-tabs" -version = "3.4.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "pygments" }, - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/27/32/ab475e252dc2b704e82a91141fa404cdd8901a5cf34958fd22afacebfccd/sphinx-tabs-3.4.5.tar.gz", hash = "sha256:ba9d0c1e3e37aaadd4b5678449eb08176770e0fc227e769b6ce747df3ceea531", size = 16070, upload-time = "2024-01-21T12:13:39.392Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/9f/4ac7dbb9f23a2ff5a10903a4f9e9f43e0ff051f63a313e989c962526e305/sphinx_tabs-3.4.5-py3-none-any.whl", hash = "sha256:92cc9473e2ecf1828ca3f6617d0efc0aa8acb06b08c56ba29d1413f2f0f6cf09", size = 9904, upload-time = "2024-01-21T12:13:37.67Z" }, -] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, -] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, -] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, -] - -[[package]] -name = "sphinxcontrib-jquery" -version = "4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "sphinx" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, -] - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, -] - -[[package]] -name = "sphinxcontrib-qthelp" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, -] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, -] - -[[package]] -name = "sqlalchemy" -version = "2.0.44" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830, upload-time = "2025-10-10T14:39:12.935Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/81/15d7c161c9ddf0900b076b55345872ed04ff1ed6a0666e5e94ab44b0163c/sqlalchemy-2.0.44-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd", size = 2140517, upload-time = "2025-10-10T15:36:15.64Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d5/4abd13b245c7d91bdf131d4916fd9e96a584dac74215f8b5bc945206a974/sqlalchemy-2.0.44-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa", size = 2130738, upload-time = "2025-10-10T15:36:16.91Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3c/8418969879c26522019c1025171cefbb2a8586b6789ea13254ac602986c0/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e", size = 3304145, upload-time = "2025-10-10T15:34:19.569Z" }, - { url = "https://files.pythonhosted.org/packages/94/2d/fdb9246d9d32518bda5d90f4b65030b9bf403a935cfe4c36a474846517cb/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e", size = 3304511, upload-time = "2025-10-10T15:47:05.088Z" }, - { url = "https://files.pythonhosted.org/packages/7d/fb/40f2ad1da97d5c83f6c1269664678293d3fe28e90ad17a1093b735420549/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399", size = 3235161, upload-time = "2025-10-10T15:34:21.193Z" }, - { url = "https://files.pythonhosted.org/packages/95/cb/7cf4078b46752dca917d18cf31910d4eff6076e5b513c2d66100c4293d83/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b", size = 3261426, upload-time = "2025-10-10T15:47:07.196Z" }, - { url = "https://files.pythonhosted.org/packages/f8/3b/55c09b285cb2d55bdfa711e778bdffdd0dc3ffa052b0af41f1c5d6e582fa/sqlalchemy-2.0.44-cp311-cp311-win32.whl", hash = "sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3", size = 2105392, upload-time = "2025-10-10T15:38:20.051Z" }, - { url = "https://files.pythonhosted.org/packages/c7/23/907193c2f4d680aedbfbdf7bf24c13925e3c7c292e813326c1b84a0b878e/sqlalchemy-2.0.44-cp311-cp311-win_amd64.whl", hash = "sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5", size = 2130293, upload-time = "2025-10-10T15:38:21.601Z" }, - { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718, upload-time = "2025-10-10T15:29:45.32Z" }, -] - -[[package]] -name = "sqlparse" -version = "0.5.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/40/edede8dd6977b0d3da179a342c198ed100dd2aba4be081861ee5911e4da4/sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", size = 84999, upload-time = "2024-12-10T12:05:30.728Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" }, -] - -[[package]] -name = "stack-data" -version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asttokens" }, - { name = "executing" }, - { name = "pure-eval" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, -] - -[[package]] -name = "sympy" -version = "1.14.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mpmath" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, -] - -[[package]] -name = "tabulate" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, -] - -[[package]] -name = "tenacity" -version = "9.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, -] - -[[package]] -name = "tensorboard" -version = "2.16.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "grpcio" }, - { name = "markdown" }, - { name = "numpy" }, - { name = "protobuf" }, - { name = "setuptools" }, - { name = "six" }, - { name = "tensorboard-data-server" }, - { name = "werkzeug" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/d0/b97889ffa769e2d1fdebb632084d5e8b53fc299d43a537acee7ec0c021a3/tensorboard-2.16.2-py3-none-any.whl", hash = "sha256:9f2b4e7dad86667615c0e5cd072f1ea8403fc032a299f0072d6f74855775cc45", size = 5490335, upload-time = "2024-02-16T19:56:55.912Z" }, -] - -[[package]] -name = "tensorboard-data-server" -version = "0.7.2" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl", hash = "sha256:7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb", size = 2356, upload-time = "2023-10-23T21:23:32.16Z" }, - { url = "https://files.pythonhosted.org/packages/b7/85/dabeaf902892922777492e1d253bb7e1264cadce3cea932f7ff599e53fea/tensorboard_data_server-0.7.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9fe5d24221b29625dbc7328b0436ca7fc1c23de4acf4d272f1180856e32f9f60", size = 4823598, upload-time = "2023-10-23T21:23:33.714Z" }, - { url = "https://files.pythonhosted.org/packages/73/c6/825dab04195756cf8ff2e12698f22513b3db2f64925bdd41671bfb33aaa5/tensorboard_data_server-0.7.2-py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:ef687163c24185ae9754ed5650eb5bc4d84ff257aabdc33f0cc6f74d8ba54530", size = 6590363, upload-time = "2023-10-23T21:23:35.583Z" }, -] - -[[package]] -name = "tensordict" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cloudpickle", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "importlib-metadata", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "numpy", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "orjson", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pyvers", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/c9/44d4106f288cef22962268b54ed2438afee32e4f8380f0ed91e7dacc9b80/tensordict-0.10.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:37af5d60593c2439d81c2dbb7d0caa0018c50a3063da18b1d4d8b7d7d0503ee0", size = 800435, upload-time = "2025-09-08T10:07:12.581Z" }, - { url = "https://files.pythonhosted.org/packages/ac/7f/46b81cd2bf98860a6e4313605eccd45d44c7490dfd60b2124534d7efbe6e/tensordict-0.10.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:369c0a2dd3cbd9d0bcf98cc389486295e683d262bb57d4a07733cd56d936f4b2", size = 444486, upload-time = "2025-09-08T10:07:13.826Z" }, - { url = "https://files.pythonhosted.org/packages/41/c1/373677e2376c25f0b01ba46907fcae33268d371bcaae45026f6fed418b77/tensordict-0.10.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:bccb6a7d7f02a8c83ca41815943bfa284da7d28019ab4276135809bda5ba05a6", size = 447610, upload-time = "2025-09-08T10:07:15.304Z" }, - { url = "https://files.pythonhosted.org/packages/37/24/acc1f329605d5e57f33650b7bb3bd5bb39b0ba0ad86b1d06c2282b668004/tensordict-0.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:07f691f73eaefa40cf285266318caac54c7527afcd149646ed3dc1af2fc45c9d", size = 493474, upload-time = "2025-09-08T10:07:16.866Z" }, -] - -[[package]] -name = "tensorflow" -version = "2.16.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "astunparse" }, - { name = "flatbuffers" }, - { name = "gast" }, - { name = "google-pasta" }, - { name = "grpcio" }, - { name = "h5py" }, - { name = "keras" }, - { name = "libclang" }, - { name = "ml-dtypes" }, - { name = "numpy" }, - { name = "opt-einsum" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "requests" }, - { name = "setuptools" }, - { name = "six" }, - { name = "tensorboard" }, - { name = "tensorflow-io-gcs-filesystem" }, - { name = "termcolor" }, - { name = "typing-extensions" }, - { name = "wrapt" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/69/9999c2d9e8a3b08dfcfc7e9259a05fb1da5f700936091d2eb4a7985c2776/tensorflow-2.16.2-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:ec06570d57bfa0e2be804405e3cdc2960e94887e7619ffb6bc053e9775b695aa", size = 259588062, upload-time = "2024-06-28T18:51:09.316Z" }, - { url = "https://files.pythonhosted.org/packages/9d/72/6f09443493b9df2fd8a9585c9af4d9453762906a8e5735a8a5efa6e3d1e3/tensorflow-2.16.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:2c8a0e79395639b762e62002db99b2f6cc608f744312c9940899c1128f325331", size = 227025342, upload-time = "2024-06-28T18:51:19.421Z" }, - { url = "https://files.pythonhosted.org/packages/b5/01/c03e98c8e97d151d9ce075fae210f838832eb53d8aa55669d384cb72925b/tensorflow-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8728b12bc86941d90d0a927c40d4b21f8820964a80439a7c45f850eb37d57067", size = 218904025, upload-time = "2024-06-28T18:51:29.52Z" }, - { url = "https://files.pythonhosted.org/packages/43/dd/8f03331107b76e63313d2089ddfbd13f15e51fb8ed73517cdd0ab3341928/tensorflow-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8798dea8e2281b4a0b569d9c00e7949c0090509be363da271e1ef21828bffae", size = 590660880, upload-time = "2024-06-28T18:51:42.788Z" }, - { url = "https://files.pythonhosted.org/packages/1f/97/dec9dfa95cfbee631adffbeb0b7eda51ddc93a5f7e8aa8f4d95dde59e69e/tensorflow-2.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:1da04e39834cdba509b4dd5ac5c71c3a1d1ffe6bc03e6970e65791b9a4071340", size = 2070, upload-time = "2024-06-28T18:51:55.409Z" }, -] - -[[package]] -name = "tensorflow-data-validation" -version = "1.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "apache-beam", extra = ["gcp"], marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "joblib", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "numpy", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pandas", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pyarrow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pyfarmhash", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "six", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tfx-bsl", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/d8/8b193132c8769d31d11e92b058cd6651b5d8cba1b91878665bdb7408260b/tensorflow_data_validation-1.16.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:b21fa86c61da5cee81b4d602953fea16878de4874eb6035bf7f3221cfeb91559", size = 20236896, upload-time = "2024-10-15T20:20:03.396Z" }, - { url = "https://files.pythonhosted.org/packages/da/4d/4e758f700f1e1b0162ff74c0dca0f0ebd8e366e57088a29ec1f3bdaf0287/tensorflow_data_validation-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2e666e724a418fb45cca17442d33f906e91c086ad4a897aaf4473c94e0f4ee", size = 18961461, upload-time = "2024-10-15T20:40:56.17Z" }, -] - -[[package]] -name = "tensorflow-io-gcs-filesystem" -version = "0.37.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/9b/b2fb82d0da673b17a334f785fc19c23483165019ddc33b275ef25ca31173/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:32c50ab4e29a23c1f91cd0f9ab8c381a0ab10f45ef5c5252e94965916041737c", size = 2470224, upload-time = "2024-07-01T23:44:23.039Z" }, - { url = "https://files.pythonhosted.org/packages/5b/cc/16634e76f3647fbec18187258da3ba11184a6232dcf9073dc44579076d36/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b02f9c5f94fd62773954a04f69b68c4d576d076fd0db4ca25d5479f0fbfcdbad", size = 3479613, upload-time = "2024-07-01T23:44:24.399Z" }, - { url = "https://files.pythonhosted.org/packages/de/bf/ba597d3884c77d05a78050f3c178933d69e3f80200a261df6eaa920656cd/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e1f2796b57e799a8ca1b75bf47c2aaa437c968408cc1a402a9862929e104cda", size = 4842079, upload-time = "2024-07-01T23:44:26.825Z" }, - { url = "https://files.pythonhosted.org/packages/66/7f/e36ae148c2f03d61ca1bff24bc13a0fef6d6825c966abef73fc6f880a23b/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee7c8ee5fe2fd8cb6392669ef16e71841133041fee8a330eff519ad9b36e4556", size = 5085736, upload-time = "2024-07-01T23:44:28.618Z" }, -] - -[[package]] -name = "tensorflow-metadata" -version = "1.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "googleapis-common-protos", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/57/393aa9dde72347cde9e01f665bac344f14adefd5c748be45b23aa5804f6d/tensorflow_metadata-1.16.1-py3-none-any.whl", hash = "sha256:2ce72ea31d78a00c0c74c6d465482335aa5cb2a3b2a104dedba0b258bc7bb18a", size = 28984, upload-time = "2024-10-09T19:57:12.683Z" }, -] - -[[package]] -name = "tensorflow-serving-api" -version = "2.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "grpcio", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/6a/6e91fbca9593663edc368df59a5d57e5549048530ba42c6833b560e30cba/tensorflow_serving_api-2.16.1-py2.py3-none-any.whl", hash = "sha256:13f859ea45055d393acd4cd8b44283ac52ff2970051fb9b96a69e0a626f07992", size = 26539, upload-time = "2024-03-22T02:01:06.207Z" }, -] - -[[package]] -name = "tensorflow-transform" -version = "1.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "apache-beam", extra = ["gcp"], marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "numpy", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pyarrow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pydot", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tf-keras", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tfx-bsl", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/a4/7610ef37f429855bd832f98377715298f66478c8e16174e9330f10bd1eed/tensorflow_transform-1.16.0-py3-none-any.whl", hash = "sha256:a2138d6c052cb5ad30ca08191d8795d2059e86d6001b2cb5a3b00d567727d7f1", size = 451456, upload-time = "2024-10-28T22:32:45.384Z" }, -] - -[[package]] -name = "termcolor" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/56/ab275c2b56a5e2342568838f0d5e3e66a32354adcc159b495e374cda43f5/termcolor-3.2.0.tar.gz", hash = "sha256:610e6456feec42c4bcd28934a8c87a06c3fa28b01561d46aa09a9881b8622c58", size = 14423, upload-time = "2025-10-25T19:11:42.586Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/d5/141f53d7c1eb2a80e6d3e9a390228c3222c27705cbe7f048d3623053f3ca/termcolor-3.2.0-py3-none-any.whl", hash = "sha256:a10343879eba4da819353c55cb8049b0933890c2ebf9ad5d3ecd2bb32ea96ea6", size = 7698, upload-time = "2025-10-25T19:11:41.536Z" }, -] - -[[package]] -name = "tf-keras" -version = "2.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/63/59a4aee62ea8999850e4b3b5d94b60fe280ca93de60d0e2958066e24d6a7/tf_keras-2.16.0.tar.gz", hash = "sha256:db53891f1ac98197c2acced98cdca8c06ba8255655a6cb7eb95ed49676118280", size = 1259784, upload-time = "2024-03-09T02:28:18.742Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/75/aa/cf09f8956d4f276f655b13674e15d8d6015fd832f9689aa9ff2a515781ab/tf_keras-2.16.0-py3-none-any.whl", hash = "sha256:b2ad0541fa7d9e92c4b7a1b96593377afb58aaff374299a6ca6be1a42f51d899", size = 1724695, upload-time = "2024-03-09T02:28:15.99Z" }, -] - -[[package]] -name = "tfx-bsl" -version = "1.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "apache-beam", extra = ["gcp"], marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "google-api-python-client", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "numpy", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pandas", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "pyarrow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "tensorflow-serving-api", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/e5/a123d09e160be09423544529883f59b89dcbfb3242218a535af2b23826f4/tfx_bsl-1.16.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:1c13ff8f4de36ceea598a5a06b9cccabb73c7b9792ca280b915abd24b6a141b5", size = 24141870, upload-time = "2024-10-14T19:08:53.096Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e7/b5f7858a63884248bc58f9ecf4d2d41d1eca66103ac742a8b6bb6ec6a075/tfx_bsl-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc767ff141f5f6b0b21ef0a0479f8294a678c0340f8f9b7e69413fb429e329a6", size = 22546327, upload-time = "2024-10-14T19:22:45.563Z" }, -] - -[[package]] -name = "threadpoolctl" -version = "3.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, -] - -[[package]] -name = "tinycss2" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, -] - -[[package]] -name = "torch" -version = "2.8.0" -source = { registry = "https://download.pytorch.org/whl/cpu" } -resolution-markers = [ - "platform_machine == 'arm64' and sys_platform == 'darwin'", -] -dependencies = [ - { name = "filelock", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, - { name = "fsspec", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, - { name = "jinja2", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, - { name = "networkx", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, - { name = "sympy", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, - { name = "typing-extensions", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, -] -wheels = [ - { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:3d05017d19bc99741288e458888283a44b0ee881d53f05f72f8b1cfea8998122" }, -] - -[[package]] -name = "torch" -version = "2.8.0+cpu" -source = { registry = "https://download.pytorch.org/whl/cpu" } -resolution-markers = [ - "sys_platform != 'darwin'", - "platform_machine != 'arm64' and sys_platform == 'darwin'", -] -dependencies = [ - { name = "filelock", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "fsspec", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "jinja2", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "networkx", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "sympy", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-extensions", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -wheels = [ - { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-linux_s390x.whl", hash = "sha256:2bfc013dd6efdc8f8223a0241d3529af9f315dffefb53ffa3bf14d3f10127da6" }, - { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:680129efdeeec3db5da3f88ee5d28c1b1e103b774aef40f9d638e2cce8f8d8d8" }, - { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cb06175284673a581dd91fb1965662ae4ecaba6e5c357aa0ea7bb8b84b6b7eeb" }, - { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_amd64.whl", hash = "sha256:7631ef49fbd38d382909525b83696dc12a55d68492ade4ace3883c62b9fc140f" }, - { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_arm64.whl", hash = "sha256:41e6fc5ec0914fcdce44ccf338b1d19a441b55cafdd741fd0bf1af3f9e4cfd14" }, -] - -[[package]] -name = "torch" -version = "2.8.0+cu128" -source = { registry = "https://download.pytorch.org/whl/cu128" } -dependencies = [ - { name = "filelock", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "fsspec", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "jinja2", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "networkx", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "nvidia-cublas-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cuda-cupti-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cuda-runtime-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cudnn-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cufft-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cufile-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-curand-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cusolver-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cusparse-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-cusparselt-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-nccl-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "nvidia-nvtx-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "sympy", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "triton", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-extensions", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -wheels = [ - { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:039b9dcdd6bdbaa10a8a5cd6be22c4cb3e3589a341e5f904cbb571ca28f55bed" }, - { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-win_amd64.whl", hash = "sha256:34c55443aafd31046a7963b63d30bc3b628ee4a704f826796c865fdfd05bb596" }, -] - -[[package]] -name = "torch-cluster" -version = "1.6.3+pt28cpu" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -resolution-markers = [ - "sys_platform != 'darwin'", -] -dependencies = [ - { name = "scipy", marker = "sys_platform != 'darwin'" }, -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torch-cluster" -version = "1.6.3+pt28cu128" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } -dependencies = [ - { name = "scipy" }, -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_cluster-1.6.3%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_cluster-1.6.3%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torch-geometric" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "numpy" }, - { name = "psutil" }, - { name = "pyparsing" }, - { name = "requests" }, - { name = "tqdm" }, - { name = "xxhash" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/75/63/b210152635902da7fe79fcdd16517fae108f457a0ed22c737e702a9afbae/torch_geometric-2.7.0.tar.gz", hash = "sha256:f9099e4aece1a9f618c84dbaac33a77f43139736698c7e8bddf3301ef1f2e8d4", size = 876725, upload-time = "2025-10-15T20:48:03.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/4dffd7300500465e0b4a2ae917dcb2ce771de0b9a772670365799a27c024/torch_geometric-2.7.0-py3-none-any.whl", hash = "sha256:6e0cd3ad824d484651ef5d308fc66c687bfcf5ba040d56d1e0fe0f81f365e292", size = 1275346, upload-time = "2025-10-15T20:48:01.949Z" }, -] - -[[package]] -name = "torch-scatter" -version = "2.1.2+pt28cpu" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -resolution-markers = [ - "sys_platform != 'darwin'", -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torch-scatter" -version = "2.1.2+pt28cu128" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_scatter-2.1.2%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_scatter-2.1.2%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torch-sparse" -version = "0.6.18+pt28cpu" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -resolution-markers = [ - "sys_platform != 'darwin'", -] -dependencies = [ - { name = "scipy", marker = "sys_platform != 'darwin'" }, -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torch-sparse" -version = "0.6.18+pt28cu128" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } -dependencies = [ - { name = "scipy" }, -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_sparse-0.6.18%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_sparse-0.6.18%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torch-spline-conv" -version = "1.2.2+pt28cpu" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -resolution-markers = [ - "sys_platform != 'darwin'", -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torch-spline-conv" -version = "1.2.2+pt28cu128" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_spline_conv-1.2.2%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_spline_conv-1.2.2%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, -] - -[[package]] -name = "torchmetrics" -version = "1.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "lightning-utilities", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "numpy", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/01/b6c344ac04b53ebe3759ba938f1406775fe7649c44ba2e27e467be4e6fe9/torchmetrics-1.0.3.tar.gz", hash = "sha256:1c20ea2f0db434334e88da6c015ddf936d43379bfb403e9dc2a7272b0eab453c", size = 432173, upload-time = "2023-08-08T15:50:49.966Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/90/9ac94af10cd1777859a92be1e8186325490654930e871f8bb219cc342868/torchmetrics-1.0.3-py3-none-any.whl", hash = "sha256:612a74ab8ebfcd4ebb38e5c370ce29a0e73af074948048f6f2233e25cf60da75", size = 731638, upload-time = "2023-08-08T15:50:47.799Z" }, -] - -[[package]] -name = "torchrec" -version = "1.3.0+cpu" -source = { registry = "https://download.pytorch.org/whl/cpu" } -resolution-markers = [ - "sys_platform != 'darwin'", -] -dependencies = [ - { name = "fbgemm-gpu", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, - { name = "iopath", marker = "sys_platform != 'darwin'" }, - { name = "pyre-extensions", marker = "sys_platform != 'darwin'" }, - { name = "tensordict", marker = "sys_platform != 'darwin'" }, - { name = "torchmetrics", marker = "sys_platform != 'darwin'" }, - { name = "tqdm", marker = "sys_platform != 'darwin'" }, -] -wheels = [ - { url = "https://download.pytorch.org/whl/cpu/torchrec-1.3.0%2Bcpu-py3-none-any.whl", hash = "sha256:be2b572625792feac1656afcac19e35448df5447d215575a4b8cb22d9220d2cf" }, -] - -[[package]] -name = "torchrec" -version = "1.3.0+cu128" -source = { registry = "https://download.pytorch.org/whl/cu128" } -dependencies = [ - { name = "fbgemm-gpu", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } }, - { name = "iopath" }, - { name = "pyre-extensions" }, - { name = "tensordict" }, - { name = "torchmetrics" }, - { name = "tqdm" }, -] -wheels = [ - { url = "https://download.pytorch.org/whl/cu128/torchrec-1.3.0%2Bcu128-py3-none-any.whl", hash = "sha256:6de7e4a70a6e95815a8f06b1dec4d982cea4d32fa7d86a10a8bb4c52b8a749b9" }, -] - -[[package]] -name = "tornado" -version = "6.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" }, - { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" }, - { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" }, - { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" }, - { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" }, - { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" }, - { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" }, - { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" }, - { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" }, -] - -[[package]] -name = "tqdm" -version = "4.67.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, -] - -[[package]] -name = "traitlets" -version = "5.14.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, -] - -[[package]] -name = "triton" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "setuptools", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/39/43325b3b651d50187e591eefa22e236b2981afcebaefd4f2fc0ea99df191/triton-3.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b70f5e6a41e52e48cfc087436c8a28c17ff98db369447bcaff3b887a3ab4467", size = 155531138, upload-time = "2025-07-30T19:58:29.908Z" }, -] - -[[package]] -name = "types-protobuf" -version = "6.32.1.20250918" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/5a/bd06c2dbb77ebd4ea764473c9c4c014c7ba94432192cb965a274f8544b9d/types_protobuf-6.32.1.20250918.tar.gz", hash = "sha256:44ce0ae98475909ca72379946ab61a4435eec2a41090821e713c17e8faf5b88f", size = 63780, upload-time = "2025-09-18T02:50:39.391Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/5a/8d93d4f4af5dc3dd62aa4f020deae746b34b1d94fb5bee1f776c6b7e9d6c/types_protobuf-6.32.1.20250918-py3-none-any.whl", hash = "sha256:22ba6133d142d11cc34d3788ad6dead2732368ebb0406eaa7790ea6ae46c8d0b", size = 77885, upload-time = "2025-09-18T02:50:38.028Z" }, -] - -[[package]] -name = "types-psutil" -version = "7.0.0.20250401" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ef/fc/3829cb113aa05c268b18369f1f003a4589216931658ebfa69e3d4931ba60/types_psutil-7.0.0.20250401.tar.gz", hash = "sha256:2a7d663c0888a079fc1643ebc109ad12e57a21c9552a9e2035da504191336dbf", size = 20273, upload-time = "2025-04-01T03:06:48.016Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/42/45e01f3bce242c0caad36b968114a00f454169df6c771c092c96727239d8/types_psutil-7.0.0.20250401-py3-none-any.whl", hash = "sha256:ed23f7140368104afe4e05a6085a5fa56fbe8c880a0f4dfe8d63e041106071ed", size = 23173, upload-time = "2025-04-01T03:06:46.701Z" }, -] - -[[package]] -name = "types-pytz" -version = "2025.2.0.20250809" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/07/e2/c774f754de26848f53f05defff5bb21dd9375a059d1ba5b5ea943cf8206e/types_pytz-2025.2.0.20250809.tar.gz", hash = "sha256:222e32e6a29bb28871f8834e8785e3801f2dc4441c715cd2082b271eecbe21e5", size = 10876, upload-time = "2025-08-09T03:14:17.453Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d0/91c24fe54e565f2344d7a6821e6c6bb099841ef09007ea6321a0bac0f808/types_pytz-2025.2.0.20250809-py3-none-any.whl", hash = "sha256:4f55ed1b43e925cf851a756fe1707e0f5deeb1976e15bf844bcaa025e8fbd0db", size = 10095, upload-time = "2025-08-09T03:14:16.674Z" }, -] - -[[package]] -name = "types-pyyaml" -version = "6.0.12.20250915" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" }, -] - -[[package]] -name = "types-requests" -version = "2.31.0.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "types-urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f9/b8/c1e8d39996b4929b918aba10dba5de07a8b3f4c8487bb61bb79882544e69/types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0", size = 15535, upload-time = "2023-09-27T06:19:38.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/a1/6f8dc74d9069e790d604ddae70cb46dcbac668f1bb08136e7b0f2f5cd3bf/types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9", size = 14516, upload-time = "2023-09-27T06:19:36.373Z" }, -] - -[[package]] -name = "types-tqdm" -version = "4.67.0.20250513" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "types-requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d4/74/a77b5179e3543853c51ce786b300cd253934477c81aab4d786dff9894724/types_tqdm-4.67.0.20250513.tar.gz", hash = "sha256:907028c8d0a8fc20072132cd0cee72a3b6c72abf32f5ff914a7749e7d13b351e", size = 17207, upload-time = "2025-05-13T03:06:17.539Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/7b/996a534691afd516f60fa3ad3f4101b38f7222fff6c1b12f508a4c817695/types_tqdm-4.67.0.20250513-py3-none-any.whl", hash = "sha256:73d2bdac28bab49235d8660aece6c415636a0fb406f7a24b39737dfc6bf6a5dd", size = 24060, upload-time = "2025-05-13T03:06:16.241Z" }, -] - -[[package]] -name = "types-urllib3" -version = "1.26.25.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239, upload-time = "2023-07-20T15:19:31.307Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377, upload-time = "2023-07-20T15:19:30.379Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, -] - -[[package]] -name = "typing-inspect" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, -] - -[[package]] -name = "tzdata" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, -] - -[[package]] -name = "tzlocal" -version = "5.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tzdata", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, -] - -[[package]] -name = "uritemplate" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/da/fa9aca2d866f932f17703b3b5edb7b17114bb261122b6e535ef0d9f618f8/uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae", size = 32806, upload-time = "2019-12-19T22:13:08.286Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/0c/60d82c077998feb631608dca3cc1fe19ac074e772bf0c24cf409b977b815/uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f", size = 15615, upload-time = "2019-12-19T22:13:06.86Z" }, -] - -[[package]] -name = "urllib3" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, -] - -[[package]] -name = "virtualenv" -version = "20.35.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib" }, - { name = "filelock" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, -] - -[[package]] -name = "wcwidth" -version = "0.2.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, -] - -[[package]] -name = "webencodings" -version = "0.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, -] - -[[package]] -name = "websocket-client" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "wheel" -version = "0.45.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" }, -] - -[[package]] -name = "wrapt" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/19/5e5bcd855d808892fe02d49219f97a50f64cd6d8313d75df3494ee97b1a3/wrapt-2.0.0.tar.gz", hash = "sha256:35a542cc7a962331d0279735c30995b024e852cf40481e384fd63caaa391cbb9", size = 81722, upload-time = "2025-10-19T23:47:54.07Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/8f/8e4c8b6da60b4205191d588cbac448fb9ff4f5ed89f4e555dc4813ab30cf/wrapt-2.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b7e221abb6c5387819db9323dac3c875b459695057449634f1111955d753c621", size = 77433, upload-time = "2025-10-19T23:45:42.543Z" }, - { url = "https://files.pythonhosted.org/packages/22/9a/01a29ccb029aa8e78241f8b53cb89ae8826c240129abbbb6ebba3416eff9/wrapt-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1147a84c8fc852426580af8b6e33138461ddbc65aa459a25ea539374d32069fa", size = 60641, upload-time = "2025-10-19T23:45:43.866Z" }, - { url = "https://files.pythonhosted.org/packages/3d/ec/e058997971428b7665b5c3665a55b18bb251ea7e08d002925e3ca017c020/wrapt-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d6691d4a711504a0bc10de789842ad6ac627bed22937b10f37a1211a8ab7bb3", size = 61526, upload-time = "2025-10-19T23:45:44.839Z" }, - { url = "https://files.pythonhosted.org/packages/70/c3/c82263503f554715aa1847e85dc75a69631a54e9d7ab0f1a55e34a22d44a/wrapt-2.0.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f460e1eb8e75a17c3918c8e35ba57625721eef2439ef0bcf05304ac278a65e1d", size = 114069, upload-time = "2025-10-19T23:45:47.223Z" }, - { url = "https://files.pythonhosted.org/packages/dc/97/d95e88a3a1bc2890a1aa47880c2762cf0eb6d231b5a64048e351cec6f071/wrapt-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:12c37784b77bf043bf65cc96c7195a5db474b8e54173208af076bdbb61df7b3e", size = 116109, upload-time = "2025-10-19T23:45:48.252Z" }, - { url = "https://files.pythonhosted.org/packages/dc/36/cba0bf954f2303897b80fa5342499b43f8c5201110dddf0d578d6841b149/wrapt-2.0.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75e5c049eb583835f7a0e0e311d9dde9bfbaac723a6dd89d052540f9b2809977", size = 112500, upload-time = "2025-10-19T23:45:45.838Z" }, - { url = "https://files.pythonhosted.org/packages/d7/2b/8cb88e63bec989f641d208acb3fd198bfdbbb4ef7dfb71f0cac3c90b07a9/wrapt-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e50bcbd5b65dac21b82319fcf18486e6ac439947e9305034b00704eb7405f553", size = 115356, upload-time = "2025-10-19T23:45:49.249Z" }, - { url = "https://files.pythonhosted.org/packages/bb/60/a6d5fb94648cd430648705bef9f4241bd22ead123ead552b6d2873ad5240/wrapt-2.0.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:06b78cb6b9320f57737a52fede882640d93cface98332d1a3df0c5696ec9ae9f", size = 111754, upload-time = "2025-10-19T23:45:51.21Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/1963854edf0592ae806307899dc7bf891e76cec19e598f55845c94603a65/wrapt-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c8349ebfc3cd98bc9105e0112dd8c8ac1f3c7cb5601f9d02248cae83a63f748", size = 113789, upload-time = "2025-10-19T23:45:52.473Z" }, - { url = "https://files.pythonhosted.org/packages/62/ec/4b1d76cb6d96ac511aaaa92efc57f528e57f06082a595b8b2663fcdb0f20/wrapt-2.0.0-cp311-cp311-win32.whl", hash = "sha256:028f19ec29e204fe725139d4a8b09f77ecfb64f8f02b7ab5ee822c85e330b68b", size = 57954, upload-time = "2025-10-19T23:45:57.03Z" }, - { url = "https://files.pythonhosted.org/packages/d4/cf/df8ff9bd64d4a75f9a9f6c1c93480a51904d0c9bd71c11994301c47d8a33/wrapt-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:c6961f05e58d919153ba311b397b7b904b907132b7b8344dde47865d4bb5ec89", size = 60308, upload-time = "2025-10-19T23:45:54.314Z" }, - { url = "https://files.pythonhosted.org/packages/69/d8/61e245fe387d58d84b3f913d5da9d909c4f239b887db692a05105aaf2a1b/wrapt-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:be7e316c2accd5a31dbcc230de19e2a846a325f8967fdea72704d00e38e6af06", size = 58822, upload-time = "2025-10-19T23:45:55.772Z" }, - { url = "https://files.pythonhosted.org/packages/00/5c/c34575f96a0a038579683c7f10fca943c15c7946037d1d254ab9db1536ec/wrapt-2.0.0-py3-none-any.whl", hash = "sha256:02482fb0df89857e35427dfb844319417e14fae05878f295ee43fa3bf3b15502", size = 43998, upload-time = "2025-10-19T23:47:52.858Z" }, -] - -[[package]] -name = "xxhash" -version = "3.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, - { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, - { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, - { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, - { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, - { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, - { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, - { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, - { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, - { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, - { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, - { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, - { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, - { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, - { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, - { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, -] - -[[package]] -name = "yarl" -version = "1.22.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, - { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, - { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, - { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, - { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, - { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, - { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, - { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, - { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, - { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, - { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, - { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, - { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, - { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, - { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, - { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, -] - -[[package]] -name = "zipp" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, -] - -[[package]] -name = "zstandard" -version = "0.25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, - { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, - { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, - { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, - { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, - { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, - { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, - { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, - { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, - { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, - { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, - { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, - { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, -] From 1b774cc1902e19b6f18d754c45eea99324d0fb31 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 21:50:45 +0000 Subject: [PATCH 091/148] update uv lock --- pyproject.toml | 9 +- uv.lock | 4941 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4946 insertions(+), 4 deletions(-) create mode 100644 uv.lock diff --git a/pyproject.toml b/pyproject.toml index 1c9c49398..e5da00a2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -247,10 +247,11 @@ torch_spline_conv = [ { extra = "pyg27-torch28-cpu", index = "pyg-torch28-cpu" }, { extra = "pyg27-torch28-cu128", index = "pyg-torch28-cu128" }, ] -# gigl-core is auto-discovered as a local package — uv sync / uv pip install -e gigl-core/ -# builds it from source via scikit-build-core. At release install time, published gigl -# and gigl-core wheels are resolved from the same GCP registry. -gigl-core = { workspace = true } +# gigl-core is a local path dependency. In dev, uv resolves it from the adjacent +# gigl-core/ directory and builds the C++ extension via scikit-build-core. +# At release install time, published gigl and gigl-core wheels are resolved +# from the same GCP registry. +gigl-core = { path = "gigl-core" } # ===================== Build/Project Configurations =========================== diff --git a/uv.lock b/uv.lock new file mode 100644 index 000000000..af2435aba --- /dev/null +++ b/uv.lock @@ -0,0 +1,4941 @@ +version = 1 +revision = 3 +requires-python = "==3.11.*" +resolution-markers = [ + "extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'", + "sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", + "platform_machine != 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", + "platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", + "extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra != 'extra-4-gigl-pyg27-torch28-cu128'", +] +required-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'linux'", + "platform_machine == 'arm64' and sys_platform == 'darwin'", +] +conflicts = [[ + { package = "gigl", extra = "pyg27-torch28-cpu" }, + { package = "gigl", extra = "pyg27-torch28-cu128" }, +]] + +[[package]] +name = "absl-py" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/c9/45ecff8055b0ce2ad2bfbf1f438b5b8605873704d50610eda05771b865a0/absl-py-1.4.0.tar.gz", hash = "sha256:d2c244d01048ba476e7c080bd2c6df5e141d211de80223460d5b3b8a2a58433d", size = 112028, upload-time = "2023-01-11T18:05:46.544Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/87/de5c32fa1b1c6c3305d576e299801d8655c175ca9557019906247b994331/absl_py-1.4.0-py3-none-any.whl", hash = "sha256:0d3fe606adfa4f7db64792dd4c7aee4ee0c38ab75dfd353b7a83ed3e957fcb47", size = 126549, upload-time = "2023-01-11T18:05:44.967Z" }, +] + +[[package]] +name = "accessible-pygments" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/f5/a20c4ac64aeaef1679e25c9983573618ff765d7aa829fa2b84ae7573169e/aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6", size = 757513, upload-time = "2026-03-31T21:57:02.146Z" }, + { url = "https://files.pythonhosted.org/packages/75/0a/39fa6c6b179b53fcb3e4b3d2b6d6cad0180854eda17060c7218540102bef/aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d", size = 506748, upload-time = "2026-03-31T21:57:04.275Z" }, + { url = "https://files.pythonhosted.org/packages/87/ec/e38ce072e724fd7add6243613f8d1810da084f54175353d25ccf9f9c7e5a/aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c", size = 501673, upload-time = "2026-03-31T21:57:06.208Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ba/3bc7525d7e2beaa11b309a70d48b0d3cfc3c2089ec6a7d0820d59c657053/aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb", size = 1763757, upload-time = "2026-03-31T21:57:07.882Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ab/e87744cf18f1bd78263aba24924d4953b41086bd3a31d22452378e9028a0/aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6", size = 1720152, upload-time = "2026-03-31T21:57:09.946Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f3/ed17a6f2d742af17b50bae2d152315ed1b164b07a5fd5cc1754d99e4dfa5/aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13", size = 1818010, upload-time = "2026-03-31T21:57:12.157Z" }, + { url = "https://files.pythonhosted.org/packages/53/06/ecbc63dc937192e2a5cb46df4d3edb21deb8225535818802f210a6ea5816/aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174", size = 1907251, upload-time = "2026-03-31T21:57:14.023Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a5/0521aa32c1ddf3aa1e71dcc466be0b7db2771907a13f18cddaa45967d97b/aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc", size = 1759969, upload-time = "2026-03-31T21:57:16.146Z" }, + { url = "https://files.pythonhosted.org/packages/f6/78/a38f8c9105199dd3b9706745865a8a59d0041b6be0ca0cc4b2ccf1bab374/aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6", size = 1616871, upload-time = "2026-03-31T21:57:17.856Z" }, + { url = "https://files.pythonhosted.org/packages/6f/41/27392a61ead8ab38072105c71aa44ff891e71653fe53d576a7067da2b4e8/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49", size = 1739844, upload-time = "2026-03-31T21:57:19.679Z" }, + { url = "https://files.pythonhosted.org/packages/6e/55/5564e7ae26d94f3214250009a0b1c65a0c6af4bf88924ccb6fdab901de28/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8", size = 1731969, upload-time = "2026-03-31T21:57:22.006Z" }, + { url = "https://files.pythonhosted.org/packages/6d/c5/705a3929149865fc941bcbdd1047b238e4a72bcb215a9b16b9d7a2e8d992/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d", size = 1795193, upload-time = "2026-03-31T21:57:24.256Z" }, + { url = "https://files.pythonhosted.org/packages/a6/19/edabed62f718d02cff7231ca0db4ef1c72504235bc467f7b67adb1679f48/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c", size = 1606477, upload-time = "2026-03-31T21:57:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/de/fc/76f80ef008675637d88d0b21584596dc27410a990b0918cb1e5776545b5b/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac", size = 1813198, upload-time = "2026-03-31T21:57:28.316Z" }, + { url = "https://files.pythonhosted.org/packages/e5/67/5b3ac26b80adb20ea541c487f73730dc8fa107d632c998f25bbbab98fcda/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3", size = 1752321, upload-time = "2026-03-31T21:57:30.549Z" }, + { url = "https://files.pythonhosted.org/packages/88/06/e4a2e49255ea23fa4feeb5ab092d90240d927c15e47b5b5c48dff5a9ce29/aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06", size = 439069, upload-time = "2026-03-31T21:57:32.388Z" }, + { url = "https://files.pythonhosted.org/packages/c0/43/8c7163a596dab4f8be12c190cf467a1e07e4734cf90eebb39f7f5d53fc6a/aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8", size = 462859, upload-time = "2026-03-31T21:57:34.455Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "alabaster" +version = "0.7.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776, upload-time = "2024-01-10T00:56:10.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511, upload-time = "2024-01-10T00:56:08.388Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d19459005ca000b6e7012f2f1ca597746cbcd1fbfe5e/antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b", size = 117034, upload-time = "2021-11-06T17:52:23.524Z" } + +[[package]] +name = "anyio" +version = "4.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, +] + +[[package]] +name = "apache-beam" +version = "2.56.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cloudpickle" }, + { name = "crcmod" }, + { name = "dill" }, + { name = "fastavro" }, + { name = "fasteners" }, + { name = "grpcio" }, + { name = "hdfs" }, + { name = "httplib2" }, + { name = "js2py" }, + { name = "jsonpickle" }, + { name = "jsonschema" }, + { name = "numpy" }, + { name = "objsize" }, + { name = "orjson" }, + { name = "packaging" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "pyarrow" }, + { name = "pyarrow-hotfix" }, + { name = "pydot" }, + { name = "pymongo" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "redis" }, + { name = "regex" }, + { name = "requests" }, + { name = "typing-extensions" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/f0/1e7e785be49727af70d82ec3466c3b83483105f70715e0163b638c72b82f/apache_beam-2.56.0.tar.gz", hash = "sha256:4d9f38ff287757a3d7045a96ecad4bf825e2fb1ca0b9da334927d7cc8b75b250", size = 2447062, upload-time = "2024-05-02T01:12:04.686Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/ca/60ffcd51f279c94adee008c0a86e0b06a0f76df5db1ab020691f97b8f6ed/apache_beam-2.56.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3359a5c3d53685346a92b328b3d1783db81fe74284720778d0ba3fa9bd4ce36", size = 5359773, upload-time = "2024-05-02T01:11:13.171Z" }, + { url = "https://files.pythonhosted.org/packages/8f/92/0d92125e17ec0077bdd1b3eee0722e7101c673b095fe35c22d093226841f/apache_beam-2.56.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:792aa9a6cbeeac75166065981a14f84e4a48cdd7967875496fea304f19a87f56", size = 15388561, upload-time = "2024-05-02T01:11:15.828Z" }, + { url = "https://files.pythonhosted.org/packages/39/28/960119472cb379a1408408ccf9c51a5b55198adc5b3829a4e924ffa0f3cb/apache_beam-2.56.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fa8c1aa4227b7c230a9f28b6bf8ccde26192e834a8ad1abe86048ede9e084a8", size = 14930223, upload-time = "2024-05-02T01:11:18.993Z" }, + { url = "https://files.pythonhosted.org/packages/31/73/56021e4e37676b3546440298661e37dde6a703b26f98a3df5ce75759f7f0/apache_beam-2.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26cc3ba00eb3ef45a106431f49ba944ccc93f28491eeedb6d7ed76c75ca39f1a", size = 15496789, upload-time = "2024-05-02T01:11:22.328Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4c/05a85bd3b65655c2bca13c8707b231e7e68268505909a774dea70bebe8f3/apache_beam-2.56.0-cp311-cp311-win32.whl", hash = "sha256:1ccc5ef981790b2a79ac3e6de4c130f8d2ee19740ee0b0619c79d3a9cf94a737", size = 4817184, upload-time = "2024-05-02T01:11:25.533Z" }, + { url = "https://files.pythonhosted.org/packages/f4/b9/dad915b0c914e22a8f8f7212310be23929e72e77e525cc97e1cd939b513a/apache_beam-2.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:ebe29410b1f4e9b65cae7b652d8956b5472a0585dcecf6bd810df6b76e49c4f8", size = 5031949, upload-time = "2024-05-02T01:11:27.659Z" }, +] + +[package.optional-dependencies] +gcp = [ + { name = "cachetools" }, + { name = "google-api-core" }, + { name = "google-apitools" }, + { name = "google-auth" }, + { name = "google-auth-httplib2" }, + { name = "google-cloud-aiplatform" }, + { name = "google-cloud-bigquery" }, + { name = "google-cloud-bigquery-storage" }, + { name = "google-cloud-bigtable" }, + { name = "google-cloud-core" }, + { name = "google-cloud-datastore" }, + { name = "google-cloud-dlp" }, + { name = "google-cloud-language" }, + { name = "google-cloud-pubsub" }, + { name = "google-cloud-pubsublite" }, + { name = "google-cloud-recommendations-ai" }, + { name = "google-cloud-spanner" }, + { name = "google-cloud-storage" }, + { name = "google-cloud-videointelligence" }, + { name = "google-cloud-vision" }, +] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, +] + +[[package]] +name = "argo-workflows" +version = "6.6.19" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/42/b1d178909d1b45899bc65fd44150645de007038f9ab6f389abd08257f484/argo_workflows-6.6.19.tar.gz", hash = "sha256:b4d18f4fe01501be71a6fee03921021a694caa96d13f78f6b4e1dce84fc0a545", size = 286753, upload-time = "2026-02-16T14:22:29.206Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/99/fddc48bd238fe2465788f2fc63e18811f9db4d7e5fff74d75e406e05c558/argo_workflows-6.6.19-py3-none-any.whl", hash = "sha256:daa77916a2c6fcee328d5aa2c2f4a6f684f27269bf26e77dc2cc0f187b9c9c0b", size = 1262875, upload-time = "2026-02-16T14:22:27.28Z" }, +] + +[[package]] +name = "astroid" +version = "3.3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/74/dfb75f9ccd592bbedb175d4a32fc643cf569d7c218508bfbd6ea7ef9c091/astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce", size = 400439, upload-time = "2025-07-13T18:04:23.177Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/0f/3b8fdc946b4d9cc8cc1e8af42c4e409468c84441b933d037e101b3d72d86/astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec", size = 275612, upload-time = "2025-07-13T18:04:21.07Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "astunparse" +version = "1.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, + { name = "wheel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/af/4182184d3c338792894f34a62672919db7ca008c89abee9b564dd34d8029/astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872", size = 18290, upload-time = "2019-12-22T18:12:13.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/03/13dde6512ad7b4557eb792fbcf0c653af6076b81e5941d36ec61f7ce6028/astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8", size = 12732, upload-time = "2019-12-22T18:12:11.297Z" }, +] + +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, +] + +[[package]] +name = "bleach" +version = "6.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, +] + +[package.optional-dependencies] +css = [ + { name = "tinycss2" }, +] + +[[package]] +name = "cachetools" +version = "5.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, +] + +[[package]] +name = "certifi" +version = "2026.4.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "chardet" +version = "7.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/b6/9df434a8eeba2e6628c465a1dfa31034228ef79b26f76f46278f4ef7e49d/chardet-7.4.3.tar.gz", hash = "sha256:cc1d4eb92a4ec1c2df3b490836ffa46922e599d34ce0bb75cf41fd2bf6303d56", size = 784800, upload-time = "2026-04-13T21:33:39.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/52/505c207f334d51e937cbaa27ff95776e16e2d120e13cbe491cd7b3a70b50/chardet-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25a862cddc6a9ac07023e808aedd297115345fbaabc2690479481ddc0f980e09", size = 870747, upload-time = "2026-04-13T21:32:56.916Z" }, + { url = "https://files.pythonhosted.org/packages/14/4b/d3c79495dee4831b8bebca2790e72cb90f0c5849c940570a7c7e5b70b952/chardet-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7005c88da26fd95d8abb8acbe6281d833e9a9181b03cf49b4546c4555389bd97", size = 853210, upload-time = "2026-04-13T21:32:58.309Z" }, + { url = "https://files.pythonhosted.org/packages/b9/99/f6a822ad1bde25a4c38dc3e770485e78e0893dfd871cd6e18ed3ea3a795e/chardet-7.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc50f28bad067393cce0af9091052c3b8df7a23115afd8ba7b2e0947f0cef1f8", size = 873625, upload-time = "2026-04-13T21:32:59.606Z" }, + { url = "https://files.pythonhosted.org/packages/b1/10/31932775c94a86814f76b41c4a772b52abfb0e6125324f32c6da1196c297/chardet-7.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3da294de1a681097848ab58bd3f2771a674f8039d2d87a5538b28856b815e9", size = 883436, upload-time = "2026-04-13T21:33:01.351Z" }, + { url = "https://files.pythonhosted.org/packages/6c/63/0f43e3acf2c436fdb32a0f904aeb03a2904d2126eed34a042a194d235926/chardet-7.4.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c45e116dd51b66226a53ade3f9f635e870de5399b90e00ce45dcc311093bf4", size = 876589, upload-time = "2026-04-13T21:33:02.636Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a6/e9b8f8a3e99602792b01fa7d0a731737615ab56d8bfd0b52935a0ef88b85/chardet-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:ccc1f83ab4bcfb901cf39e0c4ba6bc6e726fc6264735f10e24ceb5cb47387578", size = 941866, upload-time = "2026-04-13T21:33:04.282Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6c/0a40afdb50a0fe041ab95553b835a8160b6cf0e81edf2ae2fe9f5224cbf9/chardet-7.4.3-py3-none-any.whl", hash = "sha256:1173b74051570cf08099d7429d92e4882d375ad4217f92a6e5240ccfb26f231e", size = 626562, upload-time = "2026-04-13T21:33:38.559Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +] + +[[package]] +name = "click" +version = "8.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" }, +] + +[[package]] +name = "cloudpickle" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/51/913ecca3970a2227cf4d5e8937df52cc28f465ac442216110b8e3323262d/cloudpickle-2.2.1.tar.gz", hash = "sha256:d89684b8de9e34a2a43b3460fbca07d09d6e25ce858df4d5a44240403b6178f5", size = 60800, upload-time = "2023-01-19T09:27:28.318Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/80/44286939ca215e88fa827b2aeb6fa3fd2b4a7af322485c7170d6f9fd96e0/cloudpickle-2.2.1-py3-none-any.whl", hash = "sha256:61f594d1f4c295fa5cd9014ceb3a1fc4a70b0de1164b94fbc2d854ccba056f9f", size = 25944, upload-time = "2023-01-19T09:27:26.341Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "comm" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, +] + +[[package]] +name = "crcmod" +version = "1.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c3bcd6c33d2473c1918e0b7f6826a043ca1245dd4e5b/crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e", size = 89670, upload-time = "2010-06-27T14:35:29.538Z" } + +[[package]] +name = "cryptography" +version = "47.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", size = 830863, upload-time = "2026-04-24T19:54:57.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", size = 7912214, upload-time = "2026-04-24T19:53:03.864Z" }, + { url = "https://files.pythonhosted.org/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", size = 4644617, upload-time = "2026-04-24T19:53:06.909Z" }, + { url = "https://files.pythonhosted.org/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", size = 4668186, upload-time = "2026-04-24T19:53:09.053Z" }, + { url = "https://files.pythonhosted.org/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", size = 4651244, upload-time = "2026-04-24T19:53:11.217Z" }, + { url = "https://files.pythonhosted.org/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", size = 5252906, upload-time = "2026-04-24T19:53:13.532Z" }, + { url = "https://files.pythonhosted.org/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", size = 4701842, upload-time = "2026-04-24T19:53:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", size = 4289313, upload-time = "2026-04-24T19:53:17.755Z" }, + { url = "https://files.pythonhosted.org/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", size = 4650964, upload-time = "2026-04-24T19:53:20.062Z" }, + { url = "https://files.pythonhosted.org/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", size = 5207817, upload-time = "2026-04-24T19:53:22.498Z" }, + { url = "https://files.pythonhosted.org/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", size = 4701544, upload-time = "2026-04-24T19:53:24.356Z" }, + { url = "https://files.pythonhosted.org/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", size = 4783536, upload-time = "2026-04-24T19:53:26.665Z" }, + { url = "https://files.pythonhosted.org/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", size = 4926106, upload-time = "2026-04-24T19:53:28.686Z" }, + { url = "https://files.pythonhosted.org/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", size = 3258581, upload-time = "2026-04-24T19:53:31.058Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", size = 3775309, upload-time = "2026-04-24T19:53:33.054Z" }, + { url = "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", size = 7904072, upload-time = "2026-04-24T19:54:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", size = 4635767, upload-time = "2026-04-24T19:54:08.519Z" }, + { url = "https://files.pythonhosted.org/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", size = 4654350, upload-time = "2026-04-24T19:54:10.795Z" }, + { url = "https://files.pythonhosted.org/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", size = 4643394, upload-time = "2026-04-24T19:54:13.275Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", size = 5225777, upload-time = "2026-04-24T19:54:15.18Z" }, + { url = "https://files.pythonhosted.org/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", size = 4688771, upload-time = "2026-04-24T19:54:17.835Z" }, + { url = "https://files.pythonhosted.org/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", size = 4270753, upload-time = "2026-04-24T19:54:19.963Z" }, + { url = "https://files.pythonhosted.org/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", size = 4642911, upload-time = "2026-04-24T19:54:21.818Z" }, + { url = "https://files.pythonhosted.org/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", size = 5181411, upload-time = "2026-04-24T19:54:24.376Z" }, + { url = "https://files.pythonhosted.org/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", size = 4688262, upload-time = "2026-04-24T19:54:26.946Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", size = 4775506, upload-time = "2026-04-24T19:54:28.926Z" }, + { url = "https://files.pythonhosted.org/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", size = 4912060, upload-time = "2026-04-24T19:54:30.869Z" }, + { url = "https://files.pythonhosted.org/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", size = 3248487, upload-time = "2026-04-24T19:54:33.494Z" }, + { url = "https://files.pythonhosted.org/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", size = 3755737, upload-time = "2026-04-24T19:54:35.408Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a0/928c9ce0d120a40a81aa99e3ba383e87337b9ac9ef9f6db02e4d7822424d/cryptography-47.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f1207974a904e005f762869996cf620e9bf79ecb4622f148550bb48e0eb35a7", size = 3909893, upload-time = "2026-04-24T19:54:38.334Z" }, + { url = "https://files.pythonhosted.org/packages/81/75/d691e284750df5d9569f2b1ce4a00a71e1d79566da83b2b3e5549c84917f/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1a405c08857258c11016777e11c02bacbe7ef596faf259305d282272a3a05cbe", size = 4587867, upload-time = "2026-04-24T19:54:40.619Z" }, + { url = "https://files.pythonhosted.org/packages/07/d6/1b90f1a4e453009730b4545286f0b39bb348d805c11181fc31544e4f9a65/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:20fdbe3e38fb67c385d233c89371fa27f9909f6ebca1cecc20c13518dae65475", size = 4627192, upload-time = "2026-04-24T19:54:42.849Z" }, + { url = "https://files.pythonhosted.org/packages/dc/53/cb358a80e9e359529f496870dd08c102aa8a4b5b9f9064f00f0d6ed5b527/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f7db373287273d8af1414cf95dc4118b13ffdc62be521997b0f2b270771fef50", size = 4587486, upload-time = "2026-04-24T19:54:44.908Z" }, + { url = "https://files.pythonhosted.org/packages/8b/57/aaa3d53876467a226f9a7a82fd14dd48058ad2de1948493442dfa16e2ffd/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:9fe6b7c64926c765f9dff301f9c1b867febcda5768868ca084e18589113732ab", size = 4626327, upload-time = "2026-04-24T19:54:47.813Z" }, + { url = "https://files.pythonhosted.org/packages/ab/9c/51f28c3550276bcf35660703ba0ab829a90b88be8cd98a71ef23c2413913/cryptography-47.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cffbba3392df0fa8629bb7f43454ee2925059ee158e23c54620b9063912b86c8", size = 3698916, upload-time = "2026-04-24T19:54:49.782Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "debugpy" +version = "1.8.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/56/c3baf5cbe4dd77427fd9aef99fcdade259ad128feeb8a786c246adb838e5/debugpy-1.8.20-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:eada6042ad88fa1571b74bd5402ee8b86eded7a8f7b827849761700aff171f1b", size = 2208318, upload-time = "2026-01-29T23:03:36.481Z" }, + { url = "https://files.pythonhosted.org/packages/9a/7d/4fa79a57a8e69fe0d9763e98d1110320f9ecd7f1f362572e3aafd7417c9d/debugpy-1.8.20-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:7de0b7dfeedc504421032afba845ae2a7bcc32ddfb07dae2c3ca5442f821c344", size = 3171493, upload-time = "2026-01-29T23:03:37.775Z" }, + { url = "https://files.pythonhosted.org/packages/7d/f2/1e8f8affe51e12a26f3a8a8a4277d6e60aa89d0a66512f63b1e799d424a4/debugpy-1.8.20-cp311-cp311-win32.whl", hash = "sha256:773e839380cf459caf73cc533ea45ec2737a5cc184cf1b3b796cd4fd98504fec", size = 5209240, upload-time = "2026-01-29T23:03:39.109Z" }, + { url = "https://files.pythonhosted.org/packages/d5/92/1cb532e88560cbee973396254b21bece8c5d7c2ece958a67afa08c9f10dc/debugpy-1.8.20-cp311-cp311-win_amd64.whl", hash = "sha256:1f7650546e0eded1902d0f6af28f787fa1f1dbdbc97ddabaf1cd963a405930cb", size = 5233481, upload-time = "2026-01-29T23:03:40.659Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + +[[package]] +name = "dill" +version = "0.3.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/11/345f3173809cea7f1a193bfbf02403fff250a3360e0e118a1630985e547d/dill-0.3.1.1.tar.gz", hash = "sha256:42d8ef819367516592a825746a18073ced42ca169ab1f5f4044134703e7a049c", size = 151986, upload-time = "2019-09-28T15:44:19.775Z" } + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "docopt" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } + +[[package]] +name = "docstring-parser" +version = "0.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/4d/f332313098c1de1b2d2ff91cf2674415cc7cddab2ca1b01ae29774bd5fdf/docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015", size = 29341, upload-time = "2026-04-14T04:09:19.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b", size = 22484, upload-time = "2026-04-14T04:09:18.638Z" }, +] + +[[package]] +name = "docutils" +version = "0.20.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/53/a5da4f2c5739cf66290fac1431ee52aff6851c7c8ffd8264f13affd7bcdd/docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b", size = 2058365, upload-time = "2023-05-16T23:39:19.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/87/f238c0670b94533ac0353a4e2a1a771a0cc73277b88bff23d3ae35a256c1/docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", size = 572666, upload-time = "2023-05-16T23:39:15.976Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "fastavro" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/5b/ccb338db71f347e3bc031d268bf6dc41e5ead63b6997b8e72af92f05e18e/fastavro-1.12.2.tar.gz", hash = "sha256:3c79502d56cf6b76210032e1c53494ddfbc73c140bccf2ef4092b3f0825323ab", size = 1030127, upload-time = "2026-04-24T14:36:01.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/77/058f3c93348624cb695399b27f3f0c1c3d1190586065797e4a48f75d4147/fastavro-1.12.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d48cd7094598a7e9d4297e8bf4bbe0dc9dc2ba4367d83dbb603e3b3c6aa35566", size = 974559, upload-time = "2026-04-24T14:36:17.172Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ef/08bbfa643addd2b98a9ce536613e2098928aa5e3ca098fd5b74f3c03b96a/fastavro-1.12.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:070c6134604bd7b6fd44409406ac50445339682b2e872885db2e859f92d22e93", size = 3352777, upload-time = "2026-04-24T14:36:19.679Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ec/55c11108529bdb59e635899f737651f729485ea5af36e128fb6560969c3d/fastavro-1.12.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b73d50978d5e57416fa68461f9f3c8f39ea39e761cb1e12f919745adefe26a7", size = 3387036, upload-time = "2026-04-24T14:36:21.794Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b3/4459f7c61804e9b42b49f02fba8fbbb041af76c7cab43cee4018532ecd00/fastavro-1.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c57a9920400166398695d92580eca21fd7a79f3c67d691ac7e20a7d1b5300735", size = 3284780, upload-time = "2026-04-24T14:36:24.193Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e3/d7f510b9b8c7b73409a6232a9a8d282faa8560f85d024d7212e4c5dff3df/fastavro-1.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:81f6108f3ac292fb6cd05758c9e531389d8fc5e94e8c949b9298f4fb0a239662", size = 3368557, upload-time = "2026-04-24T14:36:26.667Z" }, + { url = "https://files.pythonhosted.org/packages/cb/10/14fa0abf8e7da07258393ae2b783dd4bb60d1fb93ad790296d27561f33ce/fastavro-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:eec44256856fd59d29d1f1d0950ace18a58e4228e7d49de5d5e1b1875b227dde", size = 446499, upload-time = "2026-04-24T14:36:28.547Z" }, + { url = "https://files.pythonhosted.org/packages/86/d2/c36f646296794c05d29a07bec84a6c56bfd285203e389a8954987ec1c515/fastavro-1.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:ecd1b23ea7f9af09c865ac8503d07afd7e6bf782d76bb83cbbdba15b7a0db807", size = 388198, upload-time = "2026-04-24T14:36:29.791Z" }, +] + +[[package]] +name = "fasteners" +version = "0.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/18/7881a99ba5244bfc82f06017316ffe93217dbbbcfa52b887caa1d4f2a6d3/fasteners-0.20.tar.gz", hash = "sha256:55dce8792a41b56f727ba6e123fcaee77fd87e638a6863cec00007bfea84c8d8", size = 25087, upload-time = "2025-08-11T10:19:37.785Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl", hash = "sha256:9422c40d1e350e4259f509fb2e608d6bc43c0136f79a00db1b49046029d0b3b7", size = 18702, upload-time = "2025-08-11T10:19:35.716Z" }, +] + +[[package]] +name = "fastjsonschema" +version = "2.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, +] + +[[package]] +name = "fbgemm-gpu" +version = "1.3.0+cpu" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "sys_platform != 'darwin'", +] +dependencies = [ + { name = "numpy" }, +] +wheels = [ + { url = "https://download-r2.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4154e803ba762906a604a72aa41685fdd49459fce55cea79d42ac7c45c8770ca", upload-time = "2025-08-22T18:49:45Z" }, + { url = "https://download-r2.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0267ec844b43028f4b9b8e14acd16276e82bb97f91b6b1078f732eb9225b20c6", upload-time = "2025-08-22T18:49:45Z" }, +] + +[[package]] +name = "fbgemm-gpu" +version = "1.3.0+cu128" +source = { registry = "https://download.pytorch.org/whl/cu128" } +dependencies = [ + { name = "numpy" }, +] +wheels = [ + { url = "https://download-r2.pytorch.org/whl/cu128/fbgemm_gpu-1.3.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:365a2c7f89e89f6d8acf3af5101cbb1651cd1cc64057fd2902feae490814cee3", upload-time = "2025-08-22T18:50:02Z" }, +] + +[[package]] +name = "filelock" +version = "3.29.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, +] + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" }, +] + +[[package]] +name = "fonttools" +version = "4.62.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/39/23ff32561ec8d45a4d48578b4d241369d9270dc50926c017570e60893701/fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40975849bac44fb0b9253d77420c6d8b523ac4dcdcefeff6e4d706838a5b80f7", size = 2871039, upload-time = "2026-03-13T13:52:33.127Z" }, + { url = "https://files.pythonhosted.org/packages/24/7f/66d3f8a9338a9b67fe6e1739f47e1cd5cee78bd3bc1206ef9b0b982289a5/fonttools-4.62.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9dde91633f77fa576879a0c76b1d89de373cae751a98ddf0109d54e173b40f14", size = 2416346, upload-time = "2026-03-13T13:52:35.676Z" }, + { url = "https://files.pythonhosted.org/packages/aa/53/5276ceba7bff95da7793a07c5284e1da901cf00341ce5e2f3273056c0cca/fonttools-4.62.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6acb4109f8bee00fec985c8c7afb02299e35e9c94b57287f3ea542f28bd0b0a7", size = 5100897, upload-time = "2026-03-13T13:52:38.102Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a1/40a5c4d8e28b0851d53a8eeeb46fbd73c325a2a9a165f290a5ed90e6c597/fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1c5c25671ce8805e0d080e2ffdeca7f1e86778c5cbfbeae86d7f866d8830517b", size = 5071078, upload-time = "2026-03-13T13:52:41.305Z" }, + { url = "https://files.pythonhosted.org/packages/e3/be/d378fca4c65ea1956fee6d90ace6e861776809cbbc5af22388a090c3c092/fonttools-4.62.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a5d8825e1140f04e6c99bb7d37a9e31c172f3bc208afbe02175339e699c710e1", size = 5076908, upload-time = "2026-03-13T13:52:44.122Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d9/ae6a1d0693a4185a84605679c8a1f719a55df87b9c6e8e817bfdd9ef5936/fonttools-4.62.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:268abb1cb221e66c014acc234e872b7870d8b5d4657a83a8f4205094c32d2416", size = 5202275, upload-time = "2026-03-13T13:52:46.591Z" }, + { url = "https://files.pythonhosted.org/packages/54/6c/af95d9c4efb15cabff22642b608342f2bd67137eea6107202d91b5b03184/fonttools-4.62.1-cp311-cp311-win32.whl", hash = "sha256:942b03094d7edbb99bdf1ae7e9090898cad7bf9030b3d21f33d7072dbcb51a53", size = 2293075, upload-time = "2026-03-13T13:52:48.711Z" }, + { url = "https://files.pythonhosted.org/packages/d3/97/bf54c5b3f2be34e1f143e6db838dfdc54f2ffa3e68c738934c82f3b2a08d/fonttools-4.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:e8514f4924375f77084e81467e63238b095abda5107620f49421c368a6017ed2", size = 2344593, upload-time = "2026-03-13T13:52:50.725Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "fsspec" +version = "2026.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/cf/b50ddf667c15276a9ab15a70ef5f257564de271957933ffea49d2cdbcdfb/fsspec-2026.3.0.tar.gz", hash = "sha256:1ee6a0e28677557f8c2f994e3eea77db6392b4de9cd1f5d7a9e87a0ae9d01b41", size = 313547, upload-time = "2026-03-27T19:11:14.892Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/1f/5f4a3cd9e4440e9d9bc78ad0a91a1c8d46b4d429d5239ebe6793c9fe5c41/fsspec-2026.3.0-py3-none-any.whl", hash = "sha256:d2ceafaad1b3457968ed14efa28798162f1638dbb5d2a6868a2db002a5ee39a4", size = 202595, upload-time = "2026-03-27T19:11:13.595Z" }, +] + +[[package]] +name = "gast" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/f6/e73969782a2ecec280f8a176f2476149dd9dba69d5f8779ec6108a7721e6/gast-0.7.0.tar.gz", hash = "sha256:0bb14cd1b806722e91ddbab6fb86bba148c22b40e7ff11e248974e04c8adfdae", size = 33630, upload-time = "2025-11-29T15:30:05.266Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/33/f1c6a276de27b7d7339a34749cc33fa87f077f921969c47185d34a887ae2/gast-0.7.0-py3-none-any.whl", hash = "sha256:99cbf1365633a74099f69c59bd650476b96baa5ef196fec88032b00b31ba36f7", size = 22966, upload-time = "2025-11-29T15:30:03.983Z" }, +] + +[[package]] +name = "gigl" +version = "0.2.0" +source = { editable = "." } +dependencies = [ + { name = "argo-workflows" }, + { name = "chardet" }, + { name = "gigl-core" }, + { name = "google-cloud-aiplatform" }, + { name = "google-cloud-dataproc" }, + { name = "google-cloud-logging" }, + { name = "google-cloud-pipeline-components" }, + { name = "google-cloud-storage" }, + { name = "ipykernel" }, + { name = "ipython" }, + { name = "kfp" }, + { name = "matplotlib" }, + { name = "mmh3" }, + { name = "msgpack" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "numpy" }, + { name = "omegaconf" }, + { name = "pandas" }, + { name = "pip" }, + { name = "protobuf" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "scikit-learn" }, + { name = "tensorflow" }, +] + +[package.optional-dependencies] +experimental = [ + { name = "hydra-core" }, +] +pyg27-torch28-cpu = [ + { name = "fbgemm-gpu", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, + { name = "pyg-lib", version = "0.6.0+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torch", version = "2.8.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch-cluster", version = "1.6.3", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "torch-cluster", version = "1.6.3+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch-geometric" }, + { name = "torch-scatter", version = "2.1.2", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "torch-scatter", version = "2.1.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch-sparse", version = "0.6.18", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "torch-sparse", version = "0.6.18+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch-spline-conv", version = "1.2.2", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "torch-spline-conv", version = "1.2.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torchrec", version = "1.5.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, +] +pyg27-torch28-cu128 = [ + { name = "fbgemm-gpu", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, + { name = "pyg-lib", version = "0.6.0+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, + { name = "torch-cluster", version = "1.6.3+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torch-geometric", marker = "sys_platform != 'darwin'" }, + { name = "torch-scatter", version = "2.1.2+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torch-sparse", version = "0.6.18+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torch-spline-conv", version = "1.2.2+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torchrec", version = "1.5.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, +] +transform = [ + { name = "apache-beam", extra = ["gcp"] }, + { name = "pyarrow" }, + { name = "tensorflow-data-validation", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow-transform", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tfx-bsl", marker = "sys_platform != 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] + +[package.dev-dependencies] +cpp-build = [ + { name = "pybind11" }, + { name = "scikit-build-core" }, +] +dev = [ + { name = "astroid" }, + { name = "mdformat" }, + { name = "mdformat-tables" }, + { name = "mistune" }, + { name = "mypy" }, + { name = "mypy-extensions" }, + { name = "mypy-protobuf" }, + { name = "myst-nb" }, + { name = "myst-parser" }, + { name = "nbconvert" }, + { name = "nbsphinx" }, + { name = "pandas-stubs" }, + { name = "parameterized" }, + { name = "pre-commit" }, + { name = "pybind11" }, + { name = "pydata-sphinx-theme" }, + { name = "ruff" }, + { name = "scikit-build-core" }, + { name = "sphinx" }, + { name = "sphinx-autoapi" }, + { name = "sphinx-autodoc-typehints" }, + { name = "sphinx-copybutton" }, + { name = "sphinx-design" }, + { name = "sphinx-hoverxref" }, + { name = "sphinx-rtd-theme" }, + { name = "sphinx-tabs" }, + { name = "types-psutil" }, + { name = "types-pyyaml" }, + { name = "types-requests" }, + { name = "types-tqdm" }, +] +docs = [ + { name = "astroid" }, + { name = "mistune" }, + { name = "myst-nb" }, + { name = "myst-parser" }, + { name = "nbconvert" }, + { name = "nbsphinx" }, + { name = "pydata-sphinx-theme" }, + { name = "sphinx" }, + { name = "sphinx-autoapi" }, + { name = "sphinx-autodoc-typehints" }, + { name = "sphinx-copybutton" }, + { name = "sphinx-design" }, + { name = "sphinx-hoverxref" }, + { name = "sphinx-rtd-theme" }, + { name = "sphinx-tabs" }, +] +lint = [ + { name = "mdformat" }, + { name = "mdformat-tables" }, + { name = "mypy" }, + { name = "mypy-extensions" }, + { name = "mypy-protobuf" }, + { name = "ruff" }, +] +test = [ + { name = "parameterized" }, +] +typing-stubs = [ + { name = "pandas-stubs" }, + { name = "types-psutil" }, + { name = "types-pyyaml" }, + { name = "types-requests" }, + { name = "types-tqdm" }, +] + +[package.metadata] +requires-dist = [ + { name = "apache-beam", extras = ["gcp"], marker = "extra == 'transform'", specifier = "==2.56.0" }, + { name = "argo-workflows" }, + { name = "chardet" }, + { name = "fbgemm-gpu", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", specifier = "~=1.3.0", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "fbgemm-gpu", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", specifier = "~=1.3.0", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, + { name = "gigl-core", directory = "gigl-core" }, + { name = "google-cloud-aiplatform" }, + { name = "google-cloud-dataproc" }, + { name = "google-cloud-logging" }, + { name = "google-cloud-pipeline-components" }, + { name = "google-cloud-storage" }, + { name = "hydra-core", marker = "extra == 'experimental'", specifier = "==1.3.2" }, + { name = "ipykernel" }, + { name = "ipython" }, + { name = "kfp", specifier = ">=2.0.0" }, + { name = "matplotlib" }, + { name = "mmh3" }, + { name = "msgpack" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "numpy" }, + { name = "omegaconf", specifier = ">=2.3.0,<3.0.0" }, + { name = "pandas" }, + { name = "pip", specifier = "~=25.3" }, + { name = "protobuf" }, + { name = "pyarrow", marker = "extra == 'transform'", specifier = "==10.0.1" }, + { name = "pyg-lib", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "pyg-lib", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "scikit-learn" }, + { name = "tensorflow", specifier = "~=2.16" }, + { name = "tensorflow-data-validation", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.1" }, + { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.1" }, + { name = "tensorflow-transform", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.0" }, + { name = "tfx-bsl", marker = "sys_platform != 'darwin' and extra == 'transform'", specifier = "==1.16.1" }, + { name = "torch", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", specifier = "==2.8", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, + { name = "torch", marker = "extra == 'pyg27-torch28-cpu'", specifier = "==2.8", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "torch-cluster", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "torch-cluster", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, + { name = "torch-geometric", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", specifier = "==2.7" }, + { name = "torch-geometric", marker = "extra == 'pyg27-torch28-cpu'", specifier = "==2.7" }, + { name = "torch-scatter", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "torch-scatter", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, + { name = "torch-sparse", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "torch-sparse", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, + { name = "torch-spline-conv", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://data.pyg.org/whl/torch-2.8.0+cpu.html", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "torch-spline-conv", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://data.pyg.org/whl/torch-2.8.0+cu128.html", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, + { name = "torchrec", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cpu'", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "gigl", extra = "pyg27-torch28-cpu" } }, + { name = "torchrec", marker = "sys_platform != 'darwin' and extra == 'pyg27-torch28-cu128'", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "gigl", extra = "pyg27-torch28-cu128" } }, +] +provides-extras = ["transform", "pyg27-torch28-cpu", "pyg27-torch28-cu128", "experimental"] + +[package.metadata.requires-dev] +cpp-build = [ + { name = "pybind11", specifier = ">=2.12" }, + { name = "scikit-build-core", specifier = ">=0.10" }, +] +dev = [ + { name = "astroid", specifier = "==3.3.11" }, + { name = "mdformat", specifier = "==0.7.22" }, + { name = "mdformat-tables", specifier = "==1.0.0" }, + { name = "mistune", specifier = ">=2.0.3" }, + { name = "mypy", specifier = "==1.8.0" }, + { name = "mypy-extensions" }, + { name = "mypy-protobuf", specifier = "==3.3.0" }, + { name = "myst-nb", specifier = "==1.2.0" }, + { name = "myst-parser", specifier = "==2.0.0" }, + { name = "nbconvert", specifier = ">=7.16.2" }, + { name = "nbsphinx", specifier = "==0.9.3" }, + { name = "pandas-stubs", specifier = "==2.2.2.240807" }, + { name = "parameterized", specifier = "==0.9.0" }, + { name = "pre-commit", specifier = "==3.3.2" }, + { name = "pybind11", specifier = ">=2.12" }, + { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, + { name = "ruff", specifier = "==0.15.10" }, + { name = "scikit-build-core", specifier = ">=0.10" }, + { name = "sphinx", specifier = "==7.4.7" }, + { name = "sphinx-autoapi", specifier = "==3.6.0" }, + { name = "sphinx-autodoc-typehints", specifier = "==2.3.0" }, + { name = "sphinx-copybutton", specifier = "==0.5.2" }, + { name = "sphinx-design", specifier = "==0.6.0" }, + { name = "sphinx-hoverxref", specifier = "==1.3.0" }, + { name = "sphinx-rtd-theme", specifier = "==2.0.0" }, + { name = "sphinx-tabs", specifier = "==3.4.5" }, + { name = "types-psutil", specifier = "==7.0.0.20250401" }, + { name = "types-pyyaml", specifier = "~=6.0.12" }, + { name = "types-requests", specifier = "==2.31.0.6" }, + { name = "types-tqdm", specifier = "==4.67.0.20250513" }, +] +docs = [ + { name = "astroid", specifier = "==3.3.11" }, + { name = "mistune", specifier = ">=2.0.3" }, + { name = "myst-nb", specifier = "==1.2.0" }, + { name = "myst-parser", specifier = "==2.0.0" }, + { name = "nbconvert", specifier = ">=7.16.2" }, + { name = "nbsphinx", specifier = "==0.9.3" }, + { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, + { name = "sphinx", specifier = "==7.4.7" }, + { name = "sphinx-autoapi", specifier = "==3.6.0" }, + { name = "sphinx-autodoc-typehints", specifier = "==2.3.0" }, + { name = "sphinx-copybutton", specifier = "==0.5.2" }, + { name = "sphinx-design", specifier = "==0.6.0" }, + { name = "sphinx-hoverxref", specifier = "==1.3.0" }, + { name = "sphinx-rtd-theme", specifier = "==2.0.0" }, + { name = "sphinx-tabs", specifier = "==3.4.5" }, +] +lint = [ + { name = "mdformat", specifier = "==0.7.22" }, + { name = "mdformat-tables", specifier = "==1.0.0" }, + { name = "mypy", specifier = "==1.8.0" }, + { name = "mypy-extensions" }, + { name = "mypy-protobuf", specifier = "==3.3.0" }, + { name = "ruff", specifier = "==0.15.10" }, +] +test = [{ name = "parameterized", specifier = "==0.9.0" }] +typing-stubs = [ + { name = "pandas-stubs", specifier = "==2.2.2.240807" }, + { name = "types-psutil", specifier = "==7.0.0.20250401" }, + { name = "types-pyyaml", specifier = "~=6.0.12" }, + { name = "types-requests", specifier = "==2.31.0.6" }, + { name = "types-tqdm", specifier = "==4.67.0.20250513" }, +] + +[[package]] +name = "gigl-core" +version = "0.2.0" +source = { directory = "gigl-core" } + +[[package]] +name = "google-api-core" +version = "2.30.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/ce/502a57fb0ec752026d24df1280b162294b22a0afb98a326084f9a979138b/google_api_core-2.30.3.tar.gz", hash = "sha256:e601a37f148585319b26db36e219df68c5d07b6382cff2d580e83404e44d641b", size = 177001, upload-time = "2026-04-10T00:41:28.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/15/e56f351cf6ef1cfea58e6ac226a7318ed1deb2218c4b3cc9bd9e4b786c5a/google_api_core-2.30.3-py3-none-any.whl", hash = "sha256:a85761ba72c444dad5d611c2220633480b2b6be2521eca69cca2dbb3ffd6bfe8", size = 173274, upload-time = "2026-04-09T22:57:16.198Z" }, +] + +[package.optional-dependencies] +grpc = [ + { name = "grpcio" }, + { name = "grpcio-status" }, +] + +[[package]] +name = "google-api-python-client" +version = "1.12.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-auth-httplib2" }, + { name = "httplib2" }, + { name = "six" }, + { name = "uritemplate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/12/07e966db6bfa4bd440af2f83ca6cc7bd61c2f4859992b7103437e8a98ce1/google-api-python-client-1.12.11.tar.gz", hash = "sha256:1b4bd42a46321e13c0542a9e4d96fa05d73626f07b39f83a73a947d70ca706a9", size = 146876, upload-time = "2022-03-15T13:49:56.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/ba/6f9604c5dadd024ec0a2f6d1789f7fbec3d53c570277966ab7376022c3d6/google_api_python_client-1.12.11-py2.py3-none-any.whl", hash = "sha256:7e0a1a265c8d3088ee1987778c72683fcb376e32bada8d7767162bd9c503fd9b", size = 62077, upload-time = "2022-03-15T13:49:54.84Z" }, +] + +[[package]] +name = "google-apitools" +version = "0.5.31" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fasteners" }, + { name = "httplib2" }, + { name = "oauth2client" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/da/aefc4cf4c168b5d875344cd9dddc77e3a2d11986b630251af5ce47dd2843/google-apitools-0.5.31.tar.gz", hash = "sha256:4af0dd6dd4582810690251f0b57a97c1873dadfda54c5bc195844c8907624170", size = 173463, upload-time = "2020-05-14T17:25:19.126Z" } + +[[package]] +name = "google-auth" +version = "2.49.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pyasn1-modules" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", size = 333958, upload-time = "2026-04-10T00:41:21.888Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", size = 240638, upload-time = "2026-04-10T00:41:14.501Z" }, +] + +[package.optional-dependencies] +requests = [ + { name = "requests" }, +] + +[[package]] +name = "google-auth-httplib2" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "httplib2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/83/7ef576d1c7ccea214e7b001e69c006bc75e058a3a1f2ab810167204b698b/google_auth_httplib2-0.2.1.tar.gz", hash = "sha256:5ef03be3927423c87fb69607b42df23a444e434ddb2555b73b3679793187b7de", size = 11086, upload-time = "2025-10-30T21:13:16.569Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/a7/ca23dd006255f70e2bc469d3f9f0c82ea455335bfd682ad4d677adc435de/google_auth_httplib2-0.2.1-py3-none-any.whl", hash = "sha256:1be94c611db91c01f9703e7f62b0a59bbd5587a95571c7b6fade510d648bc08b", size = 9525, upload-time = "2025-10-30T21:13:15.758Z" }, +] + +[[package]] +name = "google-cloud-aiplatform" +version = "1.148.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docstring-parser" }, + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-bigquery" }, + { name = "google-cloud-resource-manager" }, + { name = "google-cloud-storage" }, + { name = "google-genai" }, + { name = "packaging" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/f3/b2a9417014c93858a2e3266134f931eefd972c2d410b25d7b8782fc6f143/google_cloud_aiplatform-1.148.1.tar.gz", hash = "sha256:75d605fba34e68714bd08e1e482755d0a6e3ae972805f809d088e686c30879e7", size = 10278758, upload-time = "2026-04-17T23:45:26.738Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/5b/e3515d7bbba602c2b0f6a0da5431785e897252443682e4735d0e6873dc8f/google_cloud_aiplatform-1.148.1-py2.py3-none-any.whl", hash = "sha256:035101e2d8e65c6a706cc3930b2452de7ddcbde50dd130320fcea0d8b03b0c5a", size = 8434481, upload-time = "2026-04-17T23:45:22.919Z" }, +] + +[[package]] +name = "google-cloud-appengine-logging" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/02/800897064ca6f1a26835cdf23939c4b93e38a30f3fb5c7cec7c01ae2edc2/google_cloud_appengine_logging-1.9.0.tar.gz", hash = "sha256:ff397f0bbc1485f979ab45767c38e0f676c9598c97c384f7412216e6ea22f805", size = 17963, upload-time = "2026-03-30T22:51:33.556Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/4a/304d42664ab2afbe7be39559c9eb3f81dd06e7ac9284f9f36f726f15939d/google_cloud_appengine_logging-1.9.0-py3-none-any.whl", hash = "sha256:bbf3a7e4dc171678f7f481259d1f68c3ae7d337530f1f2361f8a0b214dbcfe36", size = 18333, upload-time = "2026-03-30T22:49:39.045Z" }, +] + +[[package]] +name = "google-cloud-audit-log" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/9f/3aedb3ce1d58c58ec7dd06b3964836eabfd17a16a95b60c8f609c0afff7f/google_cloud_audit_log-0.5.0.tar.gz", hash = "sha256:3b32d5e77db634c46fbd6c5e01f5bda836f420dfbb21d730501c75e9fab4e4a4", size = 44670, upload-time = "2026-03-30T22:50:42.295Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/40/79fa535b6e3321d5e07b2a9ab4bb63860d3fea12230c765837881348003c/google_cloud_audit_log-0.5.0-py3-none-any.whl", hash = "sha256:3f4632f25bf67446fa9085c52868f3cb42fb1afbab9489ba8978e30991afc79f", size = 44862, upload-time = "2026-03-30T22:47:57.533Z" }, +] + +[[package]] +name = "google-cloud-bigquery" +version = "3.41.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-resumable-media" }, + { name = "packaging" }, + { name = "python-dateutil" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/13/6515c7aab55a4a0cf708ffd309fb9af5bab54c13e32dc22c5acd6497193c/google_cloud_bigquery-3.41.0.tar.gz", hash = "sha256:2217e488b47ed576360c9b2cc07d59d883a54b83167c0ef37f915c26b01a06fe", size = 513434, upload-time = "2026-03-30T22:50:55.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/33/1d3902efadef9194566d499d61507e1f038454e0b55499d2d7f8ab2a4fee/google_cloud_bigquery-3.41.0-py3-none-any.whl", hash = "sha256:2a5b5a737b401cbd824a6e5eac7554100b878668d908e6548836b5d8aaa4dcaa", size = 262343, upload-time = "2026-03-30T22:48:45.444Z" }, +] + +[[package]] +name = "google-cloud-bigquery-storage" +version = "2.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/31/5c6fa9e7b8e266a765ec80d13a2b2852cb0a6d3733572e7dbdc0cb39003c/google_cloud_bigquery_storage-2.37.0.tar.gz", hash = "sha256:f88ee7f1e49db1e639da3d9a8b79835ca4bc47afbb514fb2adfc0ccb41a7fd97", size = 310578, upload-time = "2026-03-30T22:51:13.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/0e/2950d4d0160300f51c7397a080b1685d3e25b40badb2c96f03d58d0ee868/google_cloud_bigquery_storage-2.37.0-py3-none-any.whl", hash = "sha256:1e319c27ef60fc31030f6e0b52e5e891e1cdd50551effe8c6f673a4c3c56fcb6", size = 306678, upload-time = "2026-03-30T22:47:42.333Z" }, +] + +[[package]] +name = "google-cloud-bigtable" +version = "2.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "grpc-google-iam-v1" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/f5/ad2a48306a7e8d5e47b5203703ce9c343389e60f025b5ea3f0c62ba92129/google_cloud_bigtable-2.36.0.tar.gz", hash = "sha256:d5987733c2f60c739f93f259d2037858411cc994ac37cdfbccb6bb159f3ca43e", size = 796035, upload-time = "2026-04-02T21:23:33.248Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/19/1cc695fa8489ef446a70ee9e983c12f4b47e0649005758035530eaec4b1c/google_cloud_bigtable-2.36.0-py3-none-any.whl", hash = "sha256:21b2f41231b7368a550b44d5b493b811b3507fcb23eb26d00005cd3f205f2207", size = 552799, upload-time = "2026-04-02T21:23:20.475Z" }, +] + +[[package]] +name = "google-cloud-core" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/24/6ca08b0a03c7b0c620427503ab00353a4ae806b848b93bcea18b6b76fde6/google_cloud_core-2.5.1.tar.gz", hash = "sha256:3dc94bdec9d05a31d9f355045ed0f369fbc0d8c665076c734f065d729800f811", size = 36078, upload-time = "2026-03-30T22:50:08.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/d9/5bb050cb32826466aa9b25f79e2ca2879fe66cb76782d4ed798dd7506151/google_cloud_core-2.5.1-py3-none-any.whl", hash = "sha256:ea62cdf502c20e3e14be8a32c05ed02113d7bef454e40ff3fab6fe1ec9f1f4e7", size = 29452, upload-time = "2026-03-30T22:48:31.567Z" }, +] + +[[package]] +name = "google-cloud-dataproc" +version = "5.27.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpc-google-iam-v1" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/93/fd399cba4c7cc9b2b56f0f686b8bf810fe374e2b6fa4682a59b9661885d1/google_cloud_dataproc-5.27.0.tar.gz", hash = "sha256:4ed0b248f0f825ce8ed3d29ddd50fa4962321b70cb045416962c1ba7b74b46ec", size = 589166, upload-time = "2026-04-13T22:27:17.991Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/da/f4b6723f048c2b89466e7a978338954fc4ed4f501c94bd6c97ec49fd8526/google_cloud_dataproc-5.27.0-py3-none-any.whl", hash = "sha256:7eec2ee649ab28747d304a3acf26a78f0703d73ea8f93a4cb85039fee4f4864f", size = 494239, upload-time = "2026-04-13T22:27:15.981Z" }, +] + +[[package]] +name = "google-cloud-datastore" +version = "2.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/69/1389655f6949d0da0c1c5a359e64aece0a199ba177b33b7a070aa86bf672/google_cloud_datastore-2.24.0.tar.gz", hash = "sha256:f087c02a6aa4ac68bbf17f0c048ae3ee355856bf09c51439bfba193741387792", size = 266157, upload-time = "2026-03-30T22:49:52.688Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/88/357efc6b331fd29155dcb92a5dfb0030a8a6feddb7bbf8a6215defbed6c7/google_cloud_datastore-2.24.0-py3-none-any.whl", hash = "sha256:81f1d1c12c2906f59507f72742545ab04c38f62ed70b0542057e3cf04a53aa65", size = 207690, upload-time = "2026-03-30T22:47:49.48Z" }, +] + +[[package]] +name = "google-cloud-dlp" +version = "3.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/fd/7cc493dedfcf2816a51034349d1961dcc0d62e5a6ad6152a62456fdf9631/google_cloud_dlp-3.36.0.tar.gz", hash = "sha256:a239a214303ca08ccdcdd7b6ee270d2ce4e4e81955a05648ffdb383204bf5ca6", size = 280086, upload-time = "2026-04-10T00:41:23.883Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/b1/f3c8a58d6c267308c26ba951003adb6b63f53516eb1e9c91981ad762a5fe/google_cloud_dlp-3.36.0-py3-none-any.whl", hash = "sha256:e215c4d74e87108449838fb81f60875f3811772f645aa0455753d74069395dec", size = 224246, upload-time = "2026-04-10T00:41:03.741Z" }, +] + +[[package]] +name = "google-cloud-language" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/d2/06ba73d3ec41b7db89ac3650b2af6a2511f02f5de6612f128c90874abb51/google_cloud_language-2.20.0.tar.gz", hash = "sha256:32844e562f7f15e9f8136186913c818513e1f40c3bd685ddd44c3b5b2855dc93", size = 187620, upload-time = "2026-03-26T22:17:14.223Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/5a/94fa67bb276c19dc2bff2b4cfdbfb6746a0238cdbb986c0cf9d17b5a1023/google_cloud_language-2.20.0-py3-none-any.whl", hash = "sha256:c290c2f6debde9e874523d03b7fdf1cef699f7360605829b087ea71be34f3988", size = 175372, upload-time = "2026-03-26T22:13:49.079Z" }, +] + +[[package]] +name = "google-cloud-logging" +version = "3.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "google-cloud-appengine-logging" }, + { name = "google-cloud-audit-log" }, + { name = "google-cloud-core" }, + { name = "grpc-google-iam-v1" }, + { name = "grpcio" }, + { name = "opentelemetry-api" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/06/253e9795a5877f35183a7175977ca47a17255fe0c8487155f48b86c83f3e/google_cloud_logging-3.15.0.tar.gz", hash = "sha256:72168a1e98bbfc27c75f0b8f630a7f5d786065f3f1f7e9e53d2d787a03693a4a", size = 294881, upload-time = "2026-03-26T22:18:36.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/fc1a0c57f95d21559ed13e381d9024e9ee9d521489707573fd10af856545/google_cloud_logging-3.15.0-py3-none-any.whl", hash = "sha256:7dcc67434c4e7181510c133d5ac8fd4ce60c23fa4158661f67e54bf440c32450", size = 234212, upload-time = "2026-03-26T22:15:16.404Z" }, +] + +[[package]] +name = "google-cloud-monitoring" +version = "2.30.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/3f/7bc306ebb006114f58fb9143aec91e1b014a11577350d8bbd6bbc38389f9/google_cloud_monitoring-2.30.0.tar.gz", hash = "sha256:a9530aa9aa246c490810dfa7be32d67e8340d19108acc99cbc02d1ed494fba76", size = 407108, upload-time = "2026-03-26T22:17:10.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/c8/666c21c470b9d6fd62ac9ee74dc265419975228f9b16f8ad72ec22e8d98b/google_cloud_monitoring-2.30.0-py3-none-any.whl", hash = "sha256:2729f3b88a4798b7757b1d9d31b6cb562bb3544e8173765e4e5cd44d8685b1ed", size = 391367, upload-time = "2026-03-26T22:15:04.088Z" }, +] + +[[package]] +name = "google-cloud-pipeline-components" +version = "2.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-cloud-aiplatform" }, + { name = "jinja2" }, + { name = "kfp" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/ab/72e202d05f4bf0c286dbda91be67689417b90c4d45431fdae58772da4956/google_cloud_pipeline_components-2.22.0-py3-none-any.whl", hash = "sha256:aea2d526b3d562246beb7a4ca983e48983448c7b8b04a4f7053374f08a927104", size = 1386885, upload-time = "2025-11-10T23:26:13.739Z" }, +] + +[[package]] +name = "google-cloud-pubsub" +version = "2.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpc-google-iam-v1" }, + { name = "grpcio" }, + { name = "grpcio-status" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-sdk" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/89/558c48382d6875335ea6cd7f6409acfbf256b9f7fbc2ad1c19976aabdb1f/google_cloud_pubsub-2.37.0.tar.gz", hash = "sha256:7c5ba9beb5236e2b83c091dd6171423dc7d6d0e989391bd09f60dbd242b29f10", size = 403391, upload-time = "2026-04-10T00:41:17.799Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/f1/bb7162ec50971b1d252e6837d05f64f185d5cfe4e08de8f706e363c305d9/google_cloud_pubsub-2.37.0-py3-none-any.whl", hash = "sha256:dd912422cf66e4ffb423b0d5391ca81bdfa408eb0f21f57adecdb6fb3b1e0bb1", size = 325136, upload-time = "2026-04-10T00:41:01.391Z" }, +] + +[[package]] +name = "google-cloud-pubsublite" +version = "1.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-cloud-pubsub" }, + { name = "grpcio" }, + { name = "grpcio-status" }, + { name = "overrides" }, + { name = "proto-plus" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/80/e494008d190bc8147d456839fbb996d0639bf4aefd47c189ac8454d96486/google_cloud_pubsublite-1.13.0.tar.gz", hash = "sha256:cc56ca57755e7665a66f0c0025ca923f7bfeb39ba408859ffe87cb840c0e82b5", size = 287447, upload-time = "2025-12-16T14:01:41.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/69/b95c2cc498c327d2e0c515ff70c72c4a6605099f4738c039fddb6a132928/google_cloud_pubsublite-1.13.0-py3-none-any.whl", hash = "sha256:00773be42f335ec0e76e0e3e6c72041c2795268433f48add29780cea41e8bd3e", size = 324080, upload-time = "2025-12-16T14:01:40.825Z" }, +] + +[[package]] +name = "google-cloud-recommendations-ai" +version = "0.10.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/4b/65546c277002cfb8df14a5fc5e914370fece901eb75f2813b7bbbbbb59e9/google_cloud_recommendations_ai-0.10.18.tar.gz", hash = "sha256:a6bccb45744fd89f038aa3e19502d1f46ea61c438dd2c08528533f8e185ec469", size = 212396, upload-time = "2025-06-11T23:10:29.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/f4/548c455fc0f93ab2ad538c0338cbc79a9d1640b82fcec06ecd2764d95384/google_cloud_recommendations_ai-0.10.18-py3-none-any.whl", hash = "sha256:c5c4b569d8be96e65dc273d18a35e44147ef62f845c8a9e8afd93474802c60c8", size = 212208, upload-time = "2025-06-11T23:10:28.03Z" }, +] + +[[package]] +name = "google-cloud-resource-manager" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpc-google-iam-v1" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/1a/13060cabf553d52d151d2afc26b39561e82853380d499dd525a0d422d9f0/google_cloud_resource_manager-1.17.0.tar.gz", hash = "sha256:0f486b62e2c58ff992a3a50fa0f4a96eef7750aa6c971bb373398ccb91828660", size = 464971, upload-time = "2026-03-26T22:17:29.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/f7/661d7a9023e877a226b5683429c3662f75a29ef45cb1464cf39adb689218/google_cloud_resource_manager-1.17.0-py3-none-any.whl", hash = "sha256:e479baf4b014a57f298e01b8279e3290b032e3476d69c8e5e1427af8f82739a5", size = 404403, upload-time = "2026-03-26T22:15:26.57Z" }, +] + +[[package]] +name = "google-cloud-spanner" +version = "3.65.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-cloud-core" }, + { name = "google-cloud-monitoring" }, + { name = "grpc-google-iam-v1" }, + { name = "grpc-interceptor" }, + { name = "mmh3" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-resourcedetector-gcp" }, + { name = "opentelemetry-sdk" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "sqlparse" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/90/b3e3c9c7b1a5ebc76d780fcda58e3a27208d5a10c6c5b78fab64dc5ea5f9/google_cloud_spanner-3.65.0.tar.gz", hash = "sha256:434139bd1439528398cd2a96e390a57182420747c214a33f317bbac64afd9c5c", size = 889154, upload-time = "2026-04-13T22:14:34.416Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/c6/0f0806253de7e1ef5943a9e30df7798c0f5dd6e840707a899975e17d4c60/google_cloud_spanner-3.65.0-py3-none-any.whl", hash = "sha256:67ca892698d9530d10c682be7c38265089088b57272af3e57f1ea7afb9e88eff", size = 614036, upload-time = "2026-04-13T22:14:32.533Z" }, +] + +[[package]] +name = "google-cloud-storage" +version = "2.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/76/4d965702e96bb67976e755bed9828fa50306dca003dbee08b67f41dd265e/google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2", size = 5535488, upload-time = "2024-12-05T01:35:06.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/94/6db383d8ee1adf45dc6c73477152b82731fa4c4a46d9c1932cc8757e0fd4/google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba", size = 131787, upload-time = "2024-12-05T01:35:04.736Z" }, +] + +[[package]] +name = "google-cloud-videointelligence" +version = "2.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/af/a1d11dc04a694f58536523c7f0cd266dff454b29b610fc57bf85afc1733f/google_cloud_videointelligence-2.19.0.tar.gz", hash = "sha256:7b320c18a0475b08dde9b60a0fbfdf8915320c20966159fad80b5594089d561e", size = 259738, upload-time = "2026-03-26T22:18:30.163Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/4f/6ae7b3f9c81c70ecf08fd56dee17356add4730e708620312d0caf5eb2d06/google_cloud_videointelligence-2.19.0-py3-none-any.whl", hash = "sha256:b11b04c2643a50dfb030c8ae16b0f50746319c986d3570f46a6b4e16bb0b1b5b", size = 288236, upload-time = "2026-03-26T22:13:21.662Z" }, +] + +[[package]] +name = "google-cloud-vision" +version = "3.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/f9/208ae25a03f822fcc7f762198cdedaefdbac4f923f72e5c39d3bdbf2ec60/google_cloud_vision-3.13.0.tar.gz", hash = "sha256:680f668d331858a3340eac41b732903d30dc69ed08020ffd1d5ca32580bdf546", size = 592075, upload-time = "2026-03-26T22:18:38.206Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/74/775192dc2a930191e821c5cd841d399576ae7bca4db98ee5cc262ac56de0/google_cloud_vision-3.13.0-py3-none-any.whl", hash = "sha256:f6979e93ad60a7e556b152de2857f7d3b9b740afd022cea1c76548ef80c29b87", size = 543152, upload-time = "2026-03-26T22:13:13.127Z" }, +] + +[[package]] +name = "google-crc32c" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/ef/21ccfaab3d5078d41efe8612e0ed0bfc9ce22475de074162a91a25f7980d/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8", size = 31298, upload-time = "2025-12-16T00:20:32.241Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b8/f8413d3f4b676136e965e764ceedec904fe38ae8de0cdc52a12d8eb1096e/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7", size = 30872, upload-time = "2025-12-16T00:33:58.785Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15", size = 33243, upload-time = "2025-12-16T00:40:21.46Z" }, + { url = "https://files.pythonhosted.org/packages/71/03/4820b3bd99c9653d1a5210cb32f9ba4da9681619b4d35b6a052432df4773/google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a", size = 33608, upload-time = "2025-12-16T00:40:22.204Z" }, + { url = "https://files.pythonhosted.org/packages/7c/43/acf61476a11437bf9733fb2f70599b1ced11ec7ed9ea760fdd9a77d0c619/google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2", size = 34439, upload-time = "2025-12-16T00:35:20.458Z" }, + { url = "https://files.pythonhosted.org/packages/52/c5/c171e4d8c44fec1422d801a6d2e5d7ddabd733eeda505c79730ee9607f07/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93", size = 28615, upload-time = "2025-12-16T00:40:29.298Z" }, + { url = "https://files.pythonhosted.org/packages/9c/97/7d75fe37a7a6ed171a2cf17117177e7aab7e6e0d115858741b41e9dd4254/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c", size = 28800, upload-time = "2025-12-16T00:40:30.322Z" }, +] + +[[package]] +name = "google-genai" +version = "1.73.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "google-auth", extra = ["requests"] }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "sniffio" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/d8/40f5f107e5a2976bbac52d421f04d14fc221b55a8f05e66be44b2f739fe6/google_genai-1.73.1.tar.gz", hash = "sha256:b637e3a3b9e2eccc46f27136d470165803de84eca52abfed2e7352081a4d5a15", size = 530998, upload-time = "2026-04-14T21:06:19.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/af/508e0528015240d710c6763f7c89ff44fab9a94a80b4377e265d692cbfd6/google_genai-1.73.1-py3-none-any.whl", hash = "sha256:af2d2287d25e42a187de19811ef33beb2e347c7e2bdb4dc8c467d78254e43a2c", size = 783595, upload-time = "2026-04-14T21:06:17.464Z" }, +] + +[[package]] +name = "google-pasta" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/35/4a/0bd53b36ff0323d10d5f24ebd67af2de10a1117f5cf4d7add90df92756f1/google-pasta-0.2.0.tar.gz", hash = "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e", size = 40430, upload-time = "2020-03-13T18:57:50.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/de/c648ef6835192e6e2cc03f40b19eeda4382c49b5bafb43d88b931c4c74ac/google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed", size = 57471, upload-time = "2020-03-13T18:57:48.872Z" }, +] + +[[package]] +name = "google-resumable-media" +version = "2.8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-crc32c" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/d1/b1ea14b93b6b78f57fc580125de44e9f593ab88dd2460f1a8a8d18f74754/google_resumable_media-2.8.2.tar.gz", hash = "sha256:f3354a182ebd193ae3f42e3ef95e6c9b10f128320de23ac7637236713b1acd70", size = 2164510, upload-time = "2026-03-30T23:34:25.369Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/f8/50bfaf4658431ff9de45c5c3935af7ab01157a4903c603cd0eee6e78e087/google_resumable_media-2.8.2-py3-none-any.whl", hash = "sha256:82b6d8ccd11765268cdd2a2123f417ec806b8eef3000a9a38dfe3033da5fb220", size = 81511, upload-time = "2026-03-30T23:34:09.671Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.74.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/18/a746c8344152d368a5aac738d4c857012f2c5d1fd2eac7e17b647a7861bd/googleapis_common_protos-1.74.0.tar.gz", hash = "sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1", size = 151254, upload-time = "2026-04-02T21:23:26.679Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/b0/be5d3329badb9230b765de6eea66b73abd5944bdeb5afb3562ddcd80ae84/googleapis_common_protos-1.74.0-py3-none-any.whl", hash = "sha256:702216f78610bb510e3f12ac3cafd281b7ac45cc5d86e90ad87e4d301a3426b5", size = 300743, upload-time = "2026-04-02T21:22:49.108Z" }, +] + +[package.optional-dependencies] +grpc = [ + { name = "grpcio" }, +] + +[[package]] +name = "greenlet" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/94/a5935717b307d7c71fe877b52b884c6af707d2d2090db118a03fbd799369/greenlet-3.4.0.tar.gz", hash = "sha256:f50a96b64dafd6169e595a5c56c9146ef80333e67d4476a65a9c55f400fc22ff", size = 195913, upload-time = "2026-04-08T17:08:00.863Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/c6/dba32cab7e3a625b011aa5647486e2d28423a48845a2998c126dd69c85e1/greenlet-3.4.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:805bebb4945094acbab757d34d6e1098be6de8966009ab9ca54f06ff492def58", size = 285504, upload-time = "2026-04-08T15:52:14.071Z" }, + { url = "https://files.pythonhosted.org/packages/54/f4/7cb5c2b1feb9a1f50e038be79980dfa969aa91979e5e3a18fdbcfad2c517/greenlet-3.4.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:439fc2f12b9b512d9dfa681c5afe5f6b3232c708d13e6f02c845e0d9f4c2d8c6", size = 605476, upload-time = "2026-04-08T16:24:37.064Z" }, + { url = "https://files.pythonhosted.org/packages/d6/af/b66ab0b2f9a4c5a867c136bf66d9599f34f21a1bcca26a2884a29c450bd9/greenlet-3.4.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a70ed1cb0295bee1df57b63bf7f46b4e56a5c93709eea769c1fec1bb23a95875", size = 618336, upload-time = "2026-04-08T16:30:56.59Z" }, + { url = "https://files.pythonhosted.org/packages/6d/31/56c43d2b5de476f77d36ceeec436328533bff960a4cba9a07616e93063ab/greenlet-3.4.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c5696c42e6bb5cfb7c6ff4453789081c66b9b91f061e5e9367fa15792644e76", size = 625045, upload-time = "2026-04-08T16:40:37.111Z" }, + { url = "https://files.pythonhosted.org/packages/e5/5c/8c5633ece6ba611d64bf2770219a98dd439921d6424e4e8cf16b0ac74ea5/greenlet-3.4.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c660bce1940a1acae5f51f0a064f1bc785d07ea16efcb4bc708090afc4d69e83", size = 613515, upload-time = "2026-04-08T15:56:32.478Z" }, + { url = "https://files.pythonhosted.org/packages/80/ca/704d4e2c90acb8bdf7ae593f5cbc95f58e82de95cc540fb75631c1054533/greenlet-3.4.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:89995ce5ddcd2896d89615116dd39b9703bfa0c07b583b85b89bf1b5d6eddf81", size = 419745, upload-time = "2026-04-08T16:43:04.022Z" }, + { url = "https://files.pythonhosted.org/packages/a9/df/950d15bca0d90a0e7395eb777903060504cdb509b7b705631e8fb69ff415/greenlet-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ee407d4d1ca9dc632265aee1c8732c4a2d60adff848057cdebfe5fe94eb2c8a2", size = 1574623, upload-time = "2026-04-08T16:26:18.596Z" }, + { url = "https://files.pythonhosted.org/packages/1a/e7/0839afab829fcb7333c9ff6d80c040949510055d2d4d63251f0d1c7c804e/greenlet-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:956215d5e355fffa7c021d168728321fd4d31fd730ac609b1653b450f6a4bc71", size = 1639579, upload-time = "2026-04-08T15:57:29.231Z" }, + { url = "https://files.pythonhosted.org/packages/d9/2b/b4482401e9bcaf9f5c97f67ead38db89c19520ff6d0d6699979c6efcc200/greenlet-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:5cb614ace7c27571270354e9c9f696554d073f8aa9319079dcba466bbdead711", size = 238233, upload-time = "2026-04-08T17:02:54.286Z" }, + { url = "https://files.pythonhosted.org/packages/0c/4d/d8123a4e0bcd583d5cfc8ddae0bbe29c67aab96711be331a7cc935a35966/greenlet-3.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:04403ac74fe295a361f650818de93be11b5038a78f49ccfb64d3b1be8fbf1267", size = 235045, upload-time = "2026-04-08T17:04:05.072Z" }, +] + +[[package]] +name = "grpc-google-iam-v1" +version = "0.14.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos", extra = ["grpc"] }, + { name = "grpcio" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/4f/d098419ad0bfc06c9ce440575f05aa22d8973b6c276e86ac7890093d3c37/grpc_google_iam_v1-0.14.4.tar.gz", hash = "sha256:392b3796947ed6334e61171d9ab06bf7eb357f554e5fc7556ad7aab6d0e17038", size = 23706, upload-time = "2026-04-01T01:57:49.813Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/22/c2dd50c09bf679bd38173656cd4402d2511e563b33bc88f90009cf50613c/grpc_google_iam_v1-0.14.4-py3-none-any.whl", hash = "sha256:412facc320fcbd94034b4df3d557662051d4d8adfa86e0ddb4dca70a3f739964", size = 32675, upload-time = "2026-04-01T01:57:47.69Z" }, +] + +[[package]] +name = "grpc-interceptor" +version = "0.15.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "grpcio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/28/57449d5567adf4c1d3e216aaca545913fbc21a915f2da6790d6734aac76e/grpc-interceptor-0.15.4.tar.gz", hash = "sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926", size = 19322, upload-time = "2023-11-16T02:05:42.459Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/ac/8d53f230a7443401ce81791ec50a3b0e54924bf615ad287654fa4a2f5cdc/grpc_interceptor-0.15.4-py3-none-any.whl", hash = "sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d", size = 20848, upload-time = "2023-11-16T02:05:40.913Z" }, +] + +[[package]] +name = "grpcio" +version = "1.80.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/db/1d56e5f5823257b291962d6c0ce106146c6447f405b60b234c4f222a7cde/grpcio-1.80.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a", size = 6055009, upload-time = "2026-03-30T08:46:46.265Z" }, + { url = "https://files.pythonhosted.org/packages/6e/18/c83f3cad64c5ca63bca7e91e5e46b0d026afc5af9d0a9972472ceba294b3/grpcio-1.80.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060", size = 12035295, upload-time = "2026-03-30T08:46:49.099Z" }, + { url = "https://files.pythonhosted.org/packages/0f/8e/e14966b435be2dda99fbe89db9525ea436edc79780431a1c2875a3582644/grpcio-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2", size = 6610297, upload-time = "2026-03-30T08:46:52.123Z" }, + { url = "https://files.pythonhosted.org/packages/cc/26/d5eb38f42ce0e3fdc8174ea4d52036ef8d58cc4426cb800f2610f625dd75/grpcio-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21", size = 7300208, upload-time = "2026-03-30T08:46:54.859Z" }, + { url = "https://files.pythonhosted.org/packages/25/51/bd267c989f85a17a5b3eea65a6feb4ff672af41ca614e5a0279cc0ea381c/grpcio-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab", size = 6813442, upload-time = "2026-03-30T08:46:57.056Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d9/d80eef735b19e9169e30164bbf889b46f9df9127598a83d174eb13a48b26/grpcio-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1", size = 7414743, upload-time = "2026-03-30T08:46:59.682Z" }, + { url = "https://files.pythonhosted.org/packages/de/f2/567f5bd5054398ed6b0509b9a30900376dcf2786bd936812098808b49d8d/grpcio-1.80.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106", size = 8426046, upload-time = "2026-03-30T08:47:02.474Z" }, + { url = "https://files.pythonhosted.org/packages/62/29/73ef0141b4732ff5eacd68430ff2512a65c004696997f70476a83e548e7e/grpcio-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6", size = 7851641, upload-time = "2026-03-30T08:47:05.462Z" }, + { url = "https://files.pythonhosted.org/packages/46/69/abbfa360eb229a8623bab5f5a4f8105e445bd38ce81a89514ba55d281ad0/grpcio-1.80.0-cp311-cp311-win32.whl", hash = "sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440", size = 4154368, upload-time = "2026-03-30T08:47:08.027Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d4/ae92206d01183b08613e846076115f5ac5991bae358d2a749fa864da5699/grpcio-1.80.0-cp311-cp311-win_amd64.whl", hash = "sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9", size = 4894235, upload-time = "2026-03-30T08:47:10.839Z" }, +] + +[[package]] +name = "grpcio-status" +version = "1.62.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/013ef01c5a1c2fd0932c27c904934162f69f41ca0f28396d3ffe4d386123/grpcio-status-1.62.3.tar.gz", hash = "sha256:289bdd7b2459794a12cf95dc0cb727bd4a1742c37bd823f760236c937e53a485", size = 13063, upload-time = "2024-08-06T00:37:08.003Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/40/972271de05f9315c0d69f9f7ebbcadd83bc85322f538637d11bb8c67803d/grpcio_status-1.62.3-py3-none-any.whl", hash = "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8", size = 14448, upload-time = "2024-08-06T00:30:15.702Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "h5py" +version = "3.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/33/acd0ce6863b6c0d7735007df01815403f5589a21ff8c2e1ee2587a38f548/h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738", size = 446526, upload-time = "2026-03-06T13:49:08.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/95/a825894f3e45cbac7554c4e97314ce886b233a20033787eda755ca8fecc7/h5py-3.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:719439d14b83f74eeb080e9650a6c7aa6d0d9ea0ca7f804347b05fac6fbf18af", size = 3721663, upload-time = "2026-03-06T13:47:49.599Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3b/38ff88b347c3e346cda1d3fc1b65a7aa75d40632228d8b8a5d7b58508c24/h5py-3.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3f0a0e136f2e95dd0b67146abb6668af4f1a69c81ef8651a2d316e8e01de447", size = 3087630, upload-time = "2026-03-06T13:47:51.249Z" }, + { url = "https://files.pythonhosted.org/packages/98/a8/2594cef906aee761601eff842c7dc598bea2b394a3e1c00966832b8eeb7c/h5py-3.16.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a6fbc5367d4046801f9b7db9191b31895f22f1c6df1f9987d667854cac493538", size = 4823472, upload-time = "2026-03-06T13:47:53.085Z" }, + { url = "https://files.pythonhosted.org/packages/52/a0/c1f604538ff6db22a0690be2dc44ab59178e115f63c917794e529356ab23/h5py-3.16.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fb1720028d99040792bb2fb31facb8da44a6f29df7697e0b84f0d79aff2e9bd3", size = 5027150, upload-time = "2026-03-06T13:47:55.043Z" }, + { url = "https://files.pythonhosted.org/packages/2e/fd/301739083c2fc4fd89950f9bcfce75d6e14b40b0ca3d40e48a8993d1722c/h5py-3.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:314b6054fe0b1051c2b0cb2df5cbdab15622fb05e80f202e3b6a5eee0d6fe365", size = 4814544, upload-time = "2026-03-06T13:47:56.893Z" }, + { url = "https://files.pythonhosted.org/packages/4c/42/2193ed41ccee78baba8fcc0cff2c925b8b9ee3793305b23e1f22c20bf4c7/h5py-3.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ffbab2fedd6581f6aa31cf1639ca2cb86e02779de525667892ebf4cc9fd26434", size = 5034013, upload-time = "2026-03-06T13:47:59.01Z" }, + { url = "https://files.pythonhosted.org/packages/f7/20/e6c0ff62ca2ad1a396a34f4380bafccaaf8791ff8fccf3d995a1fc12d417/h5py-3.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d1f1630f92ad74494a9a7392ab25982ce2b469fc62da6074c0ce48366a2999", size = 3191673, upload-time = "2026-03-06T13:48:00.626Z" }, + { url = "https://files.pythonhosted.org/packages/f2/48/239cbe352ac4f2b8243a8e620fa1a2034635f633731493a7ff1ed71e8658/h5py-3.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:85b9c49dd58dc44cf70af944784e2c2038b6f799665d0dcbbc812a26e0faa859", size = 2673834, upload-time = "2026-03-06T13:48:02.579Z" }, +] + +[[package]] +name = "hdfs" +version = "2.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docopt" }, + { name = "requests" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/c7/1be559eb10cb7cac0d26373f18656c8037553619ddd4098e50b04ea8b4ab/hdfs-2.7.3.tar.gz", hash = "sha256:752a21e43f82197dce43697c73f454ba490838108c73a57a9247efb66d1c0479", size = 43540, upload-time = "2023-10-13T00:06:06.144Z" } + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httplib2" +version = "0.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/ad/2371116b22d616c194aa25ec410c9c6c37f23599dcd590502b74db197584/httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81", size = 351116, upload-time = "2023-03-21T22:29:37.214Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/6c/d2fbdaaa5959339d53ba38e94c123e4e84b8fbc4b84beb0e70d7c1608486/httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc", size = 96854, upload-time = "2023-03-21T22:29:35.683Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "hydra-core" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "antlr4-python3-runtime" }, + { name = "omegaconf" }, + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/8e/07e42bc434a847154083b315779b0a81d567154504624e181caf2c71cd98/hydra-core-1.3.2.tar.gz", hash = "sha256:8a878ed67216997c3e9d88a8e72e7b4767e81af37afb4ea3334b269a4390a824", size = 3263494, upload-time = "2023-02-23T18:33:43.03Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/50/e0edd38dcd63fb26a8547f13d28f7a008bc4a3fd4eb4ff030673f22ad41a/hydra_core-1.3.2-py3-none-any.whl", hash = "sha256:fa0238a9e31df3373b35b0bfb672c34cc92718d21f81311d8996a16de1141d8b", size = 154547, upload-time = "2023-02-23T18:33:40.801Z" }, +] + +[[package]] +name = "identify" +version = "2.6.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, +] + +[[package]] +name = "idna" +version = "3.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, +] + +[[package]] +name = "imagesize" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/e6/7bf14eeb8f8b7251141944835abd42eb20a658d89084b7e1f3e5fe394090/imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3", size = 1773045, upload-time = "2026-03-03T14:18:29.941Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, +] + +[[package]] +name = "iopath" +version = "0.1.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "portalocker" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/73/b3d451dfc523756cf177d3ebb0af76dc7751b341c60e2a21871be400ae29/iopath-0.1.10.tar.gz", hash = "sha256:3311c16a4d9137223e20f141655759933e1eda24f8bff166af834af3c645ef01", size = 42226, upload-time = "2022-07-09T19:00:50.866Z" } + +[[package]] +name = "ipykernel" +version = "7.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e", size = 176046, upload-time = "2026-02-06T16:43:27.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/b9/e73d5d9f405cba7706c539aa8b311b49d4c2f3d698d9c12f815231169c71/ipykernel-7.2.0-py3-none-any.whl", hash = "sha256:3bbd4420d2b3cc105cbdf3756bfc04500b1e52f090a90716851f3916c62e1661", size = 118788, upload-time = "2026-02-06T16:43:25.149Z" }, +] + +[[package]] +name = "ipython" +version = "9.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "(sys_platform != 'emscripten' and sys_platform != 'win32') or (sys_platform == 'emscripten' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform == 'win32' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "prompt-toolkit" }, + { name = "psutil" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/87cda5842cf5c31837c06ddb588e11c3c35d8ece89b7a0108c06b8c9b00a/ipython-9.13.0.tar.gz", hash = "sha256:7e834b6afc99f020e3f05966ced34792f40267d64cb1ea9043886dab0dde5967", size = 4430549, upload-time = "2026-04-24T12:24:55.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/86/3060e8029b7cc505cce9a0137431dda81d0a3fde93a8f0f50ee0bf37a795/ipython-9.13.0-py3-none-any.whl", hash = "sha256:57f9d4639e20818d328d287c7b549af3d05f12486ea8f2e7f73e52a36ec4d201", size = 627274, upload-time = "2026-04-24T12:24:53.038Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, +] + +[[package]] +name = "js2py" +version = "0.74" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyjsparser" }, + { name = "six" }, + { name = "tzlocal" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/a5/3d8b3e4511cc21479f78f359b1b21f1fb7c640988765ffd09e55c6605e3b/Js2Py-0.74.tar.gz", hash = "sha256:39f3a6aa8469180efba3c8677271df27c31332fd1b471df1af2af58b87b8972f", size = 2504984, upload-time = "2022-11-06T10:43:53.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/58/2feb430d47c9f18f331494b429697342722b51f28dad8ad92a511c0f6fc8/Js2Py-0.74-py3-none-any.whl", hash = "sha256:40a508a79e2f8d624e3f2e604f90a1e6f46ac75b416d7f4745939ff4a2e95e09", size = 1033007, upload-time = "2022-11-06T10:43:50.988Z" }, +] + +[[package]] +name = "jsonpickle" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/d9/05365407d3312653498001adcebe64a14024f7189691b728610209991c46/jsonpickle-3.4.2.tar.gz", hash = "sha256:2efa2778859b6397d5804b0a98d52cd2a7d9a70fcb873bc5a3ca5acca8f499ba", size = 314339, upload-time = "2024-11-06T07:48:25.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/a3/e610ae0feba3e7374da08ab6cc9bb76c8bfa84b4e502aa357bda0ef6dcae/jsonpickle-3.4.2-py3-none-any.whl", hash = "sha256:fd6c273278a02b3b66e3405db3dd2f4dbc8f4a4a3123bfcab3045177c6feb9c3", size = 46256, upload-time = "2024-11-06T07:48:22.923Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "jupyter-cache" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "click" }, + { name = "importlib-metadata" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "pyyaml" }, + { name = "sqlalchemy" }, + { name = "tabulate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/f7/3627358075f183956e8c4974603232b03afd4ddc7baf72c2bc9fff522291/jupyter_cache-1.0.1.tar.gz", hash = "sha256:16e808eb19e3fb67a223db906e131ea6e01f03aa27f49a7214ce6a5fec186fb9", size = 32048, upload-time = "2024-11-15T16:03:55.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl", hash = "sha256:9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6", size = 33907, upload-time = "2024-11-15T16:03:54.021Z" }, +] + +[[package]] +name = "jupyter-client" +version = "8.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020, upload-time = "2026-01-08T13:55:47.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371, upload-time = "2026-01-08T13:55:45.562Z" }, +] + +[[package]] +name = "jupyter-core" +version = "5.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, +] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, +] + +[[package]] +name = "keras" +version = "3.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "h5py" }, + { name = "ml-dtypes" }, + { name = "namex" }, + { name = "numpy" }, + { name = "optree" }, + { name = "packaging" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/88/ce/47874047a49eedc2a5d3b41bc4f1f572bb637f51e4351ef3538e49a63800/keras-3.14.0.tar.gz", hash = "sha256:86fcf8249a25264a566ac393c287c7ad657000e5e62615dcaad4b3472a17aeda", size = 1263098, upload-time = "2026-04-03T01:42:16.386Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/20/78d26f81115d570bdf0e57d19b81de9ad8aa55ddb68eb10c8f0699fccb63/keras-3.14.0-py3-none-any.whl", hash = "sha256:19ce94b798caaba4d404ab6ef4753b44219170e5c2868156de8bb0494a260114", size = 1627362, upload-time = "2026-04-03T01:42:11.606Z" }, +] + +[[package]] +name = "kfp" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "docstring-parser" }, + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-storage" }, + { name = "kfp-pipeline-spec" }, + { name = "kfp-server-api" }, + { name = "kubernetes" }, + { name = "protobuf" }, + { name = "pyyaml" }, + { name = "requests-toolbelt" }, + { name = "tabulate" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/8e/cc5418e615c6923914911b43971c04509bf06153b6113e9e64ecdcc9e8c3/kfp-2.13.0.tar.gz", hash = "sha256:bd3e820452157472614217849f7a1cfd9c5d0d3cc7473ace80b6494ca06e8886", size = 269066, upload-time = "2025-04-28T20:55:18.863Z" } + +[[package]] +name = "kfp-pipeline-spec" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/c4/5a42b32bddae9884b0ab23135f39e49ddb510b56ba9990757c6f873b87ae/kfp_pipeline_spec-0.6.0-py3-none-any.whl", hash = "sha256:9e319b62eaa54c6790a96f796d34f071458c9cae9585c662629eb090688555a7", size = 9081, upload-time = "2024-12-06T19:48:34.321Z" }, +] + +[[package]] +name = "kfp-server-api" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "python-dateutil" }, + { name = "six" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/5c/10c7cd96cee27da45a1b90d2a95f7ec76876673fdcb0c391110ec7e75089/kfp_server_api-2.4.0.tar.gz", hash = "sha256:9d71ce49fc6757af14b052cc47e4cb531cb4e4584c2ea76ec02b9197ee9a674f", size = 83953, upload-time = "2025-02-28T00:30:13.583Z" } + +[[package]] +name = "kiwisolver" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/dd/a495a9c104be1c476f0386e714252caf2b7eca883915422a64c50b88c6f5/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c", size = 122798, upload-time = "2026-03-09T13:12:58.963Z" }, + { url = "https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb", size = 66216, upload-time = "2026-03-09T13:13:00.155Z" }, + { url = "https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac", size = 63911, upload-time = "2026-03-09T13:13:01.671Z" }, + { url = "https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27", size = 1438209, upload-time = "2026-03-09T13:13:03.385Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d6/76621246f5165e5372f02f5e6f3f48ea336a8f9e96e43997d45b240ed8cd/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398", size = 1248888, upload-time = "2026-03-09T13:13:05.231Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c1/31559ec6fb39a5b48035ce29bb63ade628f321785f38c384dee3e2c08bc1/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db", size = 1266304, upload-time = "2026-03-09T13:13:06.743Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ef/1cb8276f2d29cc6a41e0a042f27946ca347d3a4a75acf85d0a16aa6dcc82/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc", size = 1319650, upload-time = "2026-03-09T13:13:08.607Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e4/5ba3cecd7ce6236ae4a80f67e5d5531287337d0e1f076ca87a5abe4cd5d0/kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679", size = 970949, upload-time = "2026-03-09T13:13:10.299Z" }, + { url = "https://files.pythonhosted.org/packages/5a/69/dc61f7ae9a2f071f26004ced87f078235b5507ab6e5acd78f40365655034/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309", size = 2199125, upload-time = "2026-03-09T13:13:11.841Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7b/abbe0f1b5afa85f8d084b73e90e5f801c0939eba16ac2e49af7c61a6c28d/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2", size = 2293783, upload-time = "2026-03-09T13:13:14.399Z" }, + { url = "https://files.pythonhosted.org/packages/8a/80/5908ae149d96d81580d604c7f8aefd0e98f4fd728cf172f477e9f2a81744/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c", size = 1960726, upload-time = "2026-03-09T13:13:16.047Z" }, + { url = "https://files.pythonhosted.org/packages/84/08/a78cb776f8c085b7143142ce479859cfec086bd09ee638a317040b6ef420/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08", size = 2464738, upload-time = "2026-03-09T13:13:17.897Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e1/65584da5356ed6cb12c63791a10b208860ac40a83de165cb6a6751a686e3/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4", size = 2270718, upload-time = "2026-03-09T13:13:19.421Z" }, + { url = "https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b", size = 73480, upload-time = "2026-03-09T13:13:20.818Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0e/2ee5debc4f77a625778fec5501ff3e8036fe361b7ee28ae402a485bb9694/kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac", size = 64930, upload-time = "2026-03-09T13:13:21.997Z" }, + { url = "https://files.pythonhosted.org/packages/e9/eb/5fcbbbf9a0e2c3a35effb88831a483345326bbc3a030a3b5b69aee647f84/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232", size = 59532, upload-time = "2026-03-09T13:15:47.047Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9b/e17104555bb4db148fd52327feea1e96be4b88e8e008b029002c281a21ab/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a", size = 57420, upload-time = "2026-03-09T13:15:48.199Z" }, + { url = "https://files.pythonhosted.org/packages/48/44/2b5b95b7aa39fb2d8d9d956e0f3d5d45aef2ae1d942d4c3ffac2f9cfed1a/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737", size = 79892, upload-time = "2026-03-09T13:15:49.694Z" }, + { url = "https://files.pythonhosted.org/packages/52/7d/7157f9bba6b455cfb4632ed411e199fc8b8977642c2b12082e1bd9e6d173/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16", size = 77603, upload-time = "2026-03-09T13:15:50.945Z" }, + { url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" }, +] + +[[package]] +name = "kubernetes" +version = "30.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "google-auth" }, + { name = "oauthlib" }, + { name = "python-dateutil" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "requests-oauthlib" }, + { name = "six" }, + { name = "urllib3" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/3c/9f29f6cab7f35df8e54f019e5719465fa97b877be2454e99f989270b4f34/kubernetes-30.1.0.tar.gz", hash = "sha256:41e4c77af9f28e7a6c314e3bd06a8c6229ddd787cad684e0ab9f69b498e98ebc", size = 887810, upload-time = "2024-06-06T15:58:30.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/2027ddede72d33be2effc087580aeba07e733a7360780ae87226f1f91bd8/kubernetes-30.1.0-py2.py3-none-any.whl", hash = "sha256:e212e8b7579031dd2e512168b617373bc1e03888d41ac4e04039240a292d478d", size = 1706042, upload-time = "2024-06-06T15:58:27.13Z" }, +] + +[[package]] +name = "libclang" +version = "18.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/5c/ca35e19a4f142adffa27e3d652196b7362fa612243e2b916845d801454fc/libclang-18.1.1.tar.gz", hash = "sha256:a1214966d08d73d971287fc3ead8dfaf82eb07fb197680d8b3859dbbbbf78250", size = 39612, upload-time = "2024-03-17T16:04:37.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/49/f5e3e7e1419872b69f6f5e82ba56e33955a74bd537d8a1f5f1eff2f3668a/libclang-18.1.1-1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:0b2e143f0fac830156feb56f9231ff8338c20aecfe72b4ffe96f19e5a1dbb69a", size = 25836045, upload-time = "2024-06-30T17:40:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e5/fc61bbded91a8830ccce94c5294ecd6e88e496cc85f6704bf350c0634b70/libclang-18.1.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:6f14c3f194704e5d09769108f03185fce7acaf1d1ae4bbb2f30a72c2400cb7c5", size = 26502641, upload-time = "2024-03-18T15:52:26.722Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/1df62b44db2583375f6a8a5e2ca5432bbdc3edb477942b9b7c848c720055/libclang-18.1.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:83ce5045d101b669ac38e6da8e58765f12da2d3aafb3b9b98d88b286a60964d8", size = 26420207, upload-time = "2024-03-17T15:00:26.63Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fc/716c1e62e512ef1c160e7984a73a5fc7df45166f2ff3f254e71c58076f7c/libclang-18.1.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:c533091d8a3bbf7460a00cb6c1a71da93bffe148f172c7d03b1c31fbf8aa2a0b", size = 24515943, upload-time = "2024-03-17T16:03:45.942Z" }, + { url = "https://files.pythonhosted.org/packages/3c/3d/f0ac1150280d8d20d059608cf2d5ff61b7c3b7f7bcf9c0f425ab92df769a/libclang-18.1.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:54dda940a4a0491a9d1532bf071ea3ef26e6dbaf03b5000ed94dd7174e8f9592", size = 23784972, upload-time = "2024-03-17T16:12:47.677Z" }, + { url = "https://files.pythonhosted.org/packages/fe/2f/d920822c2b1ce9326a4c78c0c2b4aa3fde610c7ee9f631b600acb5376c26/libclang-18.1.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:cf4a99b05376513717ab5d82a0db832c56ccea4fd61a69dbb7bccf2dfb207dbe", size = 20259606, upload-time = "2024-03-17T16:17:42.437Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c2/de1db8c6d413597076a4259cea409b83459b2db997c003578affdd32bf66/libclang-18.1.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:69f8eb8f65c279e765ffd28aaa7e9e364c776c17618af8bff22a8df58677ff4f", size = 24921494, upload-time = "2024-03-17T16:14:20.132Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2d/3f480b1e1d31eb3d6de5e3ef641954e5c67430d5ac93b7fa7e07589576c7/libclang-18.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:4dd2d3b82fab35e2bf9ca717d7b63ac990a3519c7e312f19fa8e86dcc712f7fb", size = 26415083, upload-time = "2024-03-17T16:42:21.703Z" }, + { url = "https://files.pythonhosted.org/packages/71/cf/e01dc4cc79779cd82d77888a88ae2fa424d93b445ad4f6c02bfc18335b70/libclang-18.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:3f0e1f49f04d3cd198985fea0511576b0aee16f9ff0e0f0cad7f9c57ec3c20e8", size = 22361112, upload-time = "2024-03-17T16:42:59.565Z" }, +] + +[[package]] +name = "lightning-utilities" +version = "0.15.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/45/7fa8f56b17dc0f0a41ec70dd307ecd6787254483549843bef4c30ab5adce/lightning_utilities-0.15.3.tar.gz", hash = "sha256:792ae0204c79f6859721ac7f386c237a33b0ed06ba775009cb894e010a842033", size = 33553, upload-time = "2026-02-22T14:48:53.348Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/f4/ead6e0e37209b07c9baa3e984ccdb0348ca370b77cea3aaea8ddbb097e00/lightning_utilities-0.15.3-py3-none-any.whl", hash = "sha256:6c55f1bee70084a1cbeaa41ada96e4b3a0fea5909e844dd335bd80f5a73c5f91", size = 31906, upload-time = "2026-02-22T14:48:52.488Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:68cfdcede415f7c8f5577b03303dd94526cdb6d11036cecdc205e08733b2d2bb", size = 8306860, upload-time = "2026-04-24T00:12:01.207Z" }, + { url = "https://files.pythonhosted.org/packages/51/18/325cd32ece1120d1da51cc4e4294c6580190699490183fc2fe8cb6d61ec5/matplotlib-3.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfca0129678bd56379db26c52b5d77ed7de314c047492fbdc763aa7501710cfb", size = 8199254, upload-time = "2026-04-24T00:12:04.239Z" }, + { url = "https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e436d155fa8a3399dc62683f8f5d0e2e50d25d0144a73edd73f82eec8f4abfb", size = 8777092, upload-time = "2026-04-24T00:12:06.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/fa/3ce7adfe9ba101748f465211660d9c6374c876b671bdb8c2bb6d347e8b94/matplotlib-3.10.9-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56fc0bd271b00025c6edfdc7c2dcd247372c8e1544971d62e1dc7c17367e8bf9", size = 9595691, upload-time = "2026-04-24T00:12:09.706Z" }, + { url = "https://files.pythonhosted.org/packages/36/c4/6960a76686ed668f2c60f84e9799ba4c0d56abdb36b1577b60c1d061d1ec/matplotlib-3.10.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5a6104ed666402ba5106d7f36e0e0cdca4e8d7fa4d39708ca88019e2835a2eb", size = 9659771, upload-time = "2026-04-24T00:12:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:d730e984eddf56974c3e72b6129c7ca462ac38dc624338f4b0b23eb23ecba00f", size = 8205112, upload-time = "2026-04-24T00:12:15.773Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ee/cb57ad4754f3e7b9174ce6ce66d9205fb827067e48a9f58ac09d7e7d6b77/matplotlib-3.10.9-cp311-cp311-win_arm64.whl", hash = "sha256:51bf0ddbdc598e060d46c16b5590708f81a1624cefbaaf62f6a81bf9285b8c80", size = 8132310, upload-time = "2026-04-24T00:12:18.645Z" }, + { url = "https://files.pythonhosted.org/packages/63/e2/9f66ca6a651a52abfe0d4964ce01439ed34f3f1e119de10ff3a07f403043/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:42fb814efabe95c06c1994d8ab5a8385f43a249e23badd3ba931d4308e5bca20", size = 8304420, upload-time = "2026-04-24T00:14:04.57Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e8/467c03568218792906aa87b5e7bb379b605e056ed0c74fe00c051786d925/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f76e640a5268850bfda54b5131b1b1941cc685e42c5fa98ed9f2d64038308cba", size = 8197981, upload-time = "2026-04-24T00:14:07.233Z" }, + { url = "https://files.pythonhosted.org/packages/6f/87/afead29192170917537934c6aff4b008c805fff7b1ccea0c79120d96beda/matplotlib-3.10.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3fc0364dfbe1d07f6d15c5ebd0c5bf89e126916e5a8667dd4a7a6e84c36653d4", size = 8774002, upload-time = "2026-04-24T00:14:09.816Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, +] + +[[package]] +name = "mdformat" +version = "0.7.22" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/eb/b5cbf2484411af039a3d4aeb53a5160fae25dd8c84af6a4243bc2f3fedb3/mdformat-0.7.22.tar.gz", hash = "sha256:eef84fa8f233d3162734683c2a8a6222227a229b9206872e6139658d99acb1ea", size = 34610, upload-time = "2025-01-30T18:00:51.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/6f/94a7344f6d634fe3563bea8b33bccedee37f2726f7807e9a58440dc91627/mdformat-0.7.22-py3-none-any.whl", hash = "sha256:61122637c9e1d9be1329054f3fa216559f0d1f722b7919b060a8c2a4ae1850e5", size = 34447, upload-time = "2025-01-30T18:00:48.708Z" }, +] + +[[package]] +name = "mdformat-tables" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdformat" }, + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/fc/995ba209096bdebdeb8893d507c7b32b7e07d9a9f2cdc2ec07529947794b/mdformat_tables-1.0.0.tar.gz", hash = "sha256:a57db1ac17c4a125da794ef45539904bb8a9592e80557d525e1f169c96daa2c8", size = 6106, upload-time = "2024-08-23T23:41:33.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/37/d78e37d14323da3f607cd1af7daf262cb87fe614a245c15ad03bb03a2706/mdformat_tables-1.0.0-py3-none-any.whl", hash = "sha256:94cd86126141b2adc3b04c08d1441eb1272b36c39146bab078249a41c7240a9a", size = 5104, upload-time = "2024-08-23T23:41:31.863Z" }, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f", size = 57205, upload-time = "2025-08-11T07:25:47.597Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mistune" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, +] + +[[package]] +name = "ml-dtypes" +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/7d/8d85fcba868758b3a546e6914e727abd8f29ea6918079f816975c9eecd63/ml_dtypes-0.3.2.tar.gz", hash = "sha256:533059bc5f1764fac071ef54598db358c167c51a718f68f5bb55e3dee79d2967", size = 692014, upload-time = "2024-01-03T19:21:23.615Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/a4/6aabb78f1569550fd77c74d2c1d008b502c8ce72776bd88b14ea6c182c9e/ml_dtypes-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:763697ab8a88d47443997a7cdf3aac7340049aed45f7521f6b0ec8a0594821fe", size = 389791, upload-time = "2024-01-03T19:21:02.844Z" }, + { url = "https://files.pythonhosted.org/packages/d1/ed/211bf2e1c66e4ec9b712c3be848a876185c7f0d5e94bf647b60e64ef32eb/ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b89b194e9501a92d289c1ffd411380baf5daafb9818109a4f49b0a1b6dce4462", size = 2185796, upload-time = "2024-01-03T19:21:04.291Z" }, + { url = "https://files.pythonhosted.org/packages/77/a0/d4ee9e3aca5b9101c590b58555820618e8201c2ccb7004eabb417ec046ac/ml_dtypes-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c34f2ba9660b21fe1034b608308a01be82bbef2a92fb8199f24dc6bad0d5226", size = 2164071, upload-time = "2024-01-03T19:21:05.78Z" }, + { url = "https://files.pythonhosted.org/packages/a4/db/1784b87285588788170f87e987bfb4bda218d62a70a81ebb66c94e7f9b95/ml_dtypes-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:6604877d567a29bfe7cc02969ae0f2425260e5335505cf5e7fefc3e5465f5655", size = 127681, upload-time = "2024-01-03T19:21:07.337Z" }, +] + +[[package]] +name = "mmh3" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/1a/edb23803a168f070ded7a3014c6d706f63b90c84ccc024f89d794a3b7a6d/mmh3-5.2.1.tar.gz", hash = "sha256:bbea5b775f0ac84945191fb83f845a6fd9a21a03ea7f2e187defac7e401616ad", size = 33775, upload-time = "2026-03-05T15:55:57.716Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/d7/3312a59df3c1cdd783f4cf0c4ee8e9decff9c5466937182e4cc7dbbfe6c5/mmh3-5.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae0f0bd7d30c0ad61b9a504e8e272cb8391eed3f1587edf933f4f6b33437450", size = 56082, upload-time = "2026-03-05T15:53:59.702Z" }, + { url = "https://files.pythonhosted.org/packages/61/96/6f617baa098ca0d2989bfec6d28b5719532cd8d8848782662f5b755f657f/mmh3-5.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9aeaf53eaa075dd63e81512522fd180097312fb2c9f476333309184285c49ce0", size = 40458, upload-time = "2026-03-05T15:54:01.548Z" }, + { url = "https://files.pythonhosted.org/packages/c1/b4/9cd284bd6062d711e13d26c04d4778ab3f690c1c38a4563e3c767ec8802e/mmh3-5.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0634581290e6714c068f4aa24020acf7880927d1f0084fa753d9799ae9610082", size = 40079, upload-time = "2026-03-05T15:54:02.743Z" }, + { url = "https://files.pythonhosted.org/packages/f6/09/a806334ce1d3d50bf782b95fcee8b3648e1e170327d4bb7b4bad2ad7d956/mmh3-5.2.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e080c0637aea036f35507e803a4778f119a9b436617694ae1c5c366805f1e997", size = 97242, upload-time = "2026-03-05T15:54:04.536Z" }, + { url = "https://files.pythonhosted.org/packages/ee/93/723e317dd9e041c4dc4566a2eb53b01ad94de31750e0b834f1643905e97c/mmh3-5.2.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db0562c5f71d18596dcd45e854cf2eeba27d7543e1a3acdafb7eef728f7fe85d", size = 103082, upload-time = "2026-03-05T15:54:06.387Z" }, + { url = "https://files.pythonhosted.org/packages/61/b5/f96121e69cc48696075071531cf574f112e1ffd08059f4bffb41210e6fc5/mmh3-5.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d9f9a3ce559a5267014b04b82956993270f63ec91765e13e9fd73daf2d2738e", size = 106054, upload-time = "2026-03-05T15:54:07.506Z" }, + { url = "https://files.pythonhosted.org/packages/82/49/192b987ec48d0b2aecf8ac285a9b11fbc00030f6b9c694664ae923458dde/mmh3-5.2.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:960b1b3efa39872ac8b6cc3a556edd6fb90ed74f08c9c45e028f1005b26aa55d", size = 112910, upload-time = "2026-03-05T15:54:09.403Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a1/03e91fd334ed0144b83343a76eb11f17434cd08f746401488cfeafb2d241/mmh3-5.2.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d30b650595fdbe32366b94cb14f30bb2b625e512bd4e1df00611f99dc5c27fd4", size = 120551, upload-time = "2026-03-05T15:54:10.587Z" }, + { url = "https://files.pythonhosted.org/packages/93/b9/b89a71d2ff35c3a764d1c066c7313fc62c7cc48fa48a4b3b0304a4a0146f/mmh3-5.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:82f3802bfc4751f420d591c5c864de538b71cea117fce67e4595c2afede08a15", size = 99096, upload-time = "2026-03-05T15:54:11.76Z" }, + { url = "https://files.pythonhosted.org/packages/36/b5/613772c1c6ed5f7b63df55eb131e887cc43720fec392777b95a79d34e640/mmh3-5.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:915e7a2418f10bd1151b1953df06d896db9783c9cfdb9a8ee1f9b3a4331ab503", size = 98524, upload-time = "2026-03-05T15:54:13.122Z" }, + { url = "https://files.pythonhosted.org/packages/5e/0e/1524566fe8eaf871e4f7bc44095929fcd2620488f402822d848df19d679c/mmh3-5.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fc78739b5ec6e4fb02301984a3d442a91406e7700efbe305071e7fd1c78278f2", size = 106239, upload-time = "2026-03-05T15:54:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/04/94/21adfa7d90a7a697137ad6de33eeff6445420ca55e433a5d4919c79bc3b5/mmh3-5.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:41aac7002a749f08727cb91babff1daf8deac317c0b1f317adc69be0e6c375d1", size = 109797, upload-time = "2026-03-05T15:54:15.819Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e6/1aacc3a219e1aa62fa65669995d4a3562b35be5200ec03680c7e4bec9676/mmh3-5.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9d8089d853c7963a8ce87fff93e2a67075c0bc08684a08ea6ad13577c38ffc38", size = 97228, upload-time = "2026-03-05T15:54:16.992Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b9/5e4cca8dcccf298add0a27f3c357bc8cf8baf821d35cdc6165e4bd5a48b0/mmh3-5.2.1-cp311-cp311-win32.whl", hash = "sha256:baeb47635cb33375dee4924cd93d7f5dcaa786c740b08423b0209b824a1ee728", size = 40751, upload-time = "2026-03-05T15:54:18.714Z" }, + { url = "https://files.pythonhosted.org/packages/72/fc/5b11d49247f499bcda591171e9cf3b6ee422b19e70aa2cef2e0ae65ca3b9/mmh3-5.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1e4ecee40ba19e6975e1120829796770325841c2f153c0e9aecca927194c6a2a", size = 41517, upload-time = "2026-03-05T15:54:19.764Z" }, + { url = "https://files.pythonhosted.org/packages/8a/5f/2a511ee8a1c2a527c77726d5231685b72312c5a1a1b7639ad66a9652aa84/mmh3-5.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:c302245fd6c33d96bd169c7ccf2513c20f4c1e417c07ce9dce107c8bc3f8411f", size = 39287, upload-time = "2026-03-05T15:54:20.904Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "msgpack" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" }, + { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" }, + { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, + { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, + { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + +[[package]] +name = "mypy" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/22/25fac51008f0a4b2186da0dba3039128bd75d3fab8c07acd3ea5894f95cc/mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07", size = 2990299, upload-time = "2023-12-21T16:29:33.134Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/c4/2ce11ff9ba6c9c9e89df5049ab2325c85e60274194d6816e352926de5684/mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae", size = 10795101, upload-time = "2023-12-21T16:29:27.049Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b7/882110d1345847ce660c51fc83b3b590b9512ec2ea44e6cfd629a7d66146/mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3", size = 9849744, upload-time = "2023-12-21T16:28:28.884Z" }, + { url = "https://files.pythonhosted.org/packages/19/c6/256f253cb3fc6b30b93a9836cf3c816a3ec09f934f7b567f693e5666d14f/mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817", size = 12391778, upload-time = "2023-12-21T16:28:17.728Z" }, + { url = "https://files.pythonhosted.org/packages/66/19/e0c9373258f3e84e1e24af357e5663e6b0058bb5c307287e9d1a473a9687/mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d", size = 12461242, upload-time = "2023-12-21T16:29:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/a9/d7/a7ee8ca5a963b5bf55a6b4bc579df77c887e7fbc0910047b7d0f7750b048/mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835", size = 9205536, upload-time = "2023-12-21T16:28:56.76Z" }, + { url = "https://files.pythonhosted.org/packages/3a/e3/b582bff8e2fc7056a8a00ec06d2ac3509fc9595af9954099ed70e0418ac3/mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d", size = 2553257, upload-time = "2023-12-21T16:28:20.857Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "mypy-protobuf" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, + { name = "types-protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/59/48f1df10f87cf87d0638dd38f54549e98cb43fcf7ce0ab6c159816e85f23/mypy-protobuf-3.3.0.tar.gz", hash = "sha256:24f3b0aecb06656e983f58e07c732a90577b9d7af3e1066fc2b663bbf0370248", size = 23640, upload-time = "2022-08-24T11:18:16.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/7b/b00434b3f508eb4bc637b83c2238cacaf1ce3cc5e540a2b76f5f99302446/mypy_protobuf-3.3.0-py3-none-any.whl", hash = "sha256:15604f6943b16c05db646903261e3b3e775cf7f7990b7c37b03d043a907b650d", size = 16001, upload-time = "2022-08-24T11:18:14.462Z" }, +] + +[[package]] +name = "myst-nb" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "ipykernel" }, + { name = "ipython" }, + { name = "jupyter-cache" }, + { name = "myst-parser" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "pyyaml" }, + { name = "sphinx" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/8f/71d983ed85b1aff17db25e447a9beb67b50a9116c7cff5cde26796d1ffd0/myst_nb-1.2.0.tar.gz", hash = "sha256:af459ec753b341952182b45b0a80b4776cebf80c9ee6aaca2a3f4027b440c9de", size = 79446, upload-time = "2025-02-07T18:27:02.176Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/98/fa9dee0caf4e1f2e895d047952bf84a64eb95102df14c82c20594c0afa5f/myst_nb-1.2.0-py3-none-any.whl", hash = "sha256:0e09909877848c0cf45e1aecee97481512efa29a0c4caa37870a03bba11c56c1", size = 80303, upload-time = "2025-02-07T18:27:00.088Z" }, +] + +[[package]] +name = "myst-parser" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "jinja2" }, + { name = "markdown-it-py" }, + { name = "mdit-py-plugins" }, + { name = "pyyaml" }, + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/c1/48ea47b78ade0bb0281f34c9e343e3ea0c681fbc81464dbfd134e983954f/myst_parser-2.0.0.tar.gz", hash = "sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead", size = 85800, upload-time = "2023-06-13T16:30:30.136Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/f6/6d61a023d758f488e36638076e8a4ec4447a2cdf86938cf6c60cf1c860e6/myst_parser-2.0.0-py3-none-any.whl", hash = "sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14", size = 77158, upload-time = "2023-06-13T16:30:27.697Z" }, +] + +[[package]] +name = "namex" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/c0/ee95b28f029c73f8d49d8f52edaed02a1d4a9acb8b69355737fdb1faa191/namex-0.1.0.tar.gz", hash = "sha256:117f03ccd302cc48e3f5c58a296838f6b89c83455ab8683a1e85f2a430aa4306", size = 6649, upload-time = "2025-05-26T23:17:38.918Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/bc/465daf1de06409cdd4532082806770ee0d8d7df434da79c76564d0f69741/namex-0.1.0-py3-none-any.whl", hash = "sha256:e2012a474502f1e2251267062aae3114611f07df4224b6e06334c57b0f2ce87c", size = 5905, upload-time = "2025-05-26T23:17:37.695Z" }, +] + +[[package]] +name = "nbclient" +version = "0.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "nbformat" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, +] + +[[package]] +name = "nbconvert" +version = "7.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "bleach", extra = ["css"] }, + { name = "defusedxml" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyterlab-pygments" }, + { name = "markupsafe" }, + { name = "mistune" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "pandocfilters" }, + { name = "pygments" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/b1/708e53fe2e429c103c6e6e159106bcf0357ac41aa4c28772bd8402339051/nbconvert-7.17.1.tar.gz", hash = "sha256:34d0d0a7e73ce3cbab6c5aae8f4f468797280b01fd8bd2ca746da8569eddd7d2", size = 865311, upload-time = "2026-04-08T00:44:14.914Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/f8/bb0a9d5f46819c821dc1f004aa2cc29b1d91453297dbf5ff20470f00f193/nbconvert-7.17.1-py3-none-any.whl", hash = "sha256:aa85c087b435e7bf1ffd03319f658e285f2b89eccab33bc1ba7025495ab3e7c8", size = 261927, upload-time = "2026-04-08T00:44:12.845Z" }, +] + +[[package]] +name = "nbformat" +version = "5.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastjsonschema" }, + { name = "jsonschema" }, + { name = "jupyter-core" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, +] + +[[package]] +name = "nbsphinx" +version = "0.9.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "jinja2" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "sphinx" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/31/85cb6129d22c75722d1e1a8db0cdaf36ab7e1e7a59189bfa275445c8ab2d/nbsphinx-0.9.3.tar.gz", hash = "sha256:ec339c8691b688f8676104a367a4b8cf3ea01fd089dc28d24dec22d563b11562", size = 171956, upload-time = "2023-08-27T10:58:10.535Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/a0/ca4aeb2f7f2608a483459a3bb486da250a7eb23eb76c9a0af154395f0cb2/nbsphinx-0.9.3-py3-none-any.whl", hash = "sha256:6e805e9627f4a358bd5720d5cbf8bf48853989c79af557afd91a5f22e163029f", size = 31039, upload-time = "2023-08-27T10:58:08.017Z" }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + +[[package]] +name = "networkx" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "numpy" +version = "1.26.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/57/baae43d14fe163fa0e4c47f307b6b2511ab8d7d30177c491960504252053/numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", size = 20630554, upload-time = "2024-02-05T23:51:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/1a/2e/151484f49fd03944c4a3ad9c418ed193cfd02724e138ac8a9505d056c582/numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", size = 13997127, upload-time = "2024-02-05T23:52:15.314Z" }, + { url = "https://files.pythonhosted.org/packages/79/ae/7e5b85136806f9dadf4878bf73cf223fe5c2636818ba3ab1c585d0403164/numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", size = 14222994, upload-time = "2024-02-05T23:52:47.569Z" }, + { url = "https://files.pythonhosted.org/packages/3a/d0/edc009c27b406c4f9cbc79274d6e46d634d139075492ad055e3d68445925/numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", size = 18252005, upload-time = "2024-02-05T23:53:15.637Z" }, + { url = "https://files.pythonhosted.org/packages/09/bf/2b1aaf8f525f2923ff6cfcf134ae5e750e279ac65ebf386c75a0cf6da06a/numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", size = 13885297, upload-time = "2024-02-05T23:53:42.16Z" }, + { url = "https://files.pythonhosted.org/packages/df/a0/4e0f14d847cfc2a633a1c8621d00724f3206cfeddeb66d35698c4e2cf3d2/numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", size = 18093567, upload-time = "2024-02-05T23:54:11.696Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b7/a734c733286e10a7f1a8ad1ae8c90f2d33bf604a96548e0a4a3a6739b468/numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", size = 5968812, upload-time = "2024-02-05T23:54:26.453Z" }, + { url = "https://files.pythonhosted.org/packages/3f/6b/5610004206cf7f8e7ad91c5a85a8c71b2f2f8051a0c0c4d5916b76d6cbb2/numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", size = 15811913, upload-time = "2024-02-05T23:54:53.933Z" }, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124, upload-time = "2025-03-07T01:43:53.556Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, + { url = "https://files.pythonhosted.org/packages/70/61/7d7b3c70186fb651d0fbd35b01dbfc8e755f69fd58f817f3d0f642df20c3/nvidia_cublas_cu12-12.8.4.1-py3-none-win_amd64.whl", hash = "sha256:47e9b82132fa8d2b4944e708049229601448aaad7e6f296f630f2d1a32de35af", size = 567544208, upload-time = "2025-03-07T01:53:30.535Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318, upload-time = "2025-03-07T01:40:10.421Z" }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, + { url = "https://files.pythonhosted.org/packages/41/bc/83f5426095d93694ae39fe1311431b5d5a9bb82e48bf0dd8e19be2765942/nvidia_cuda_cupti_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:bb479dcdf7e6d4f8b0b01b115260399bf34154a1a2e9fe11c85c517d87efd98e", size = 7015759, upload-time = "2025-03-07T01:51:11.355Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076, upload-time = "2025-03-07T01:41:59.817Z" }, + { url = "https://files.pythonhosted.org/packages/45/51/52a3d84baa2136cc8df15500ad731d74d3a1114d4c123e043cb608d4a32b/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:7a4b6b2904850fe78e0bd179c4b655c404d4bb799ef03ddc60804247099ae909", size = 73586838, upload-time = "2025-03-07T01:52:13.483Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265, upload-time = "2025-03-07T01:39:43.533Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, + { url = "https://files.pythonhosted.org/packages/30/a5/a515b7600ad361ea14bfa13fb4d6687abf500adc270f19e89849c0590492/nvidia_cuda_runtime_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:c0c6027f01505bfed6c3b21ec546f69c687689aad5f1a377554bc6ca4aa993a8", size = 944318, upload-time = "2025-03-07T01:51:01.794Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878, upload-time = "2025-06-06T21:52:51.348Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, + { url = "https://files.pythonhosted.org/packages/3d/90/0bd6e586701b3a890fd38aa71c387dab4883d619d6e5ad912ccbd05bfd67/nvidia_cudnn_cu12-9.10.2.21-py3-none-win_amd64.whl", hash = "sha256:c6288de7d63e6cf62988f0923f96dc339cea362decb1bf5b3141883392a7d65e", size = 692992268, upload-time = "2025-06-06T21:55:18.114Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211, upload-time = "2025-03-07T01:44:56.873Z" }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, + { url = "https://files.pythonhosted.org/packages/7d/ec/ce1629f1e478bb5ccd208986b5f9e0316a78538dd6ab1d0484f012f8e2a1/nvidia_cufft_cu12-11.3.3.83-py3-none-win_amd64.whl", hash = "sha256:7a64a98ef2a7c47f905aaf8931b69a3a43f27c55530c698bb2ed7c75c0b42cb7", size = 192216559, upload-time = "2025-03-07T01:53:57.106Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705, upload-time = "2025-03-07T01:45:41.434Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754, upload-time = "2025-03-07T01:46:10.735Z" }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, + { url = "https://files.pythonhosted.org/packages/b9/75/70c05b2f3ed5be3bb30b7102b6eb78e100da4bbf6944fd6725c012831cab/nvidia_curand_cu12-10.3.9.90-py3-none-win_amd64.whl", hash = "sha256:f149a8ca457277da854f89cf282d6ef43176861926c7ac85b2a0fbd237c587ec", size = 62765309, upload-time = "2025-03-07T01:54:20.478Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "nvidia-cusparse-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "nvidia-nvjitlink-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841, upload-time = "2025-03-07T01:46:54.356Z" }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, + { url = "https://files.pythonhosted.org/packages/13/c0/76ca8551b8a84146ffa189fec81c26d04adba4bc0dbe09cd6e6fd9b7de04/nvidia_cusolver_cu12-11.7.3.90-py3-none-win_amd64.whl", hash = "sha256:4a550db115fcabc4d495eb7d39ac8b58d4ab5d8e63274d3754df1c0ad6a22d34", size = 256720438, upload-time = "2025-03-07T01:54:39.898Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129, upload-time = "2025-03-07T01:47:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, + { url = "https://files.pythonhosted.org/packages/62/07/f3b2ad63f8e3d257a599f422ae34eb565e70c41031aecefa3d18b62cabd1/nvidia_cusparse_cu12-12.5.8.93-py3-none-win_amd64.whl", hash = "sha256:9a33604331cb2cac199f2e7f5104dfbb8a5a898c367a53dfda9ff2acb6b6b4dd", size = 284937404, upload-time = "2025-03-07T01:55:07.742Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557, upload-time = "2025-02-26T00:16:54.265Z" }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d8/a6b0d0d0c2435e9310f3e2bb0d9c9dd4c33daef86aa5f30b3681defd37ea/nvidia_cusparselt_cu12-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f67fbb5831940ec829c9117b7f33807db9f9678dc2a617fbe781cac17b4e1075", size = 271020911, upload-time = "2025-02-26T00:14:47.204Z" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/7b/8354b784cf73b0ba51e566b4baba3ddd44fe8288a3d39ef1e06cd5417226/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ddf1a245abc36c550870f26d537a9b6087fb2e2e3d6e0ef03374c6fd19d984f", size = 322397768, upload-time = "2025-06-03T21:57:30.234Z" }, + { url = "https://files.pythonhosted.org/packages/5c/5b/4e4fff7bad39adf89f735f2bc87248c81db71205b62bcc0d5ca5b606b3c3/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039", size = 322364134, upload-time = "2025-06-03T21:58:04.013Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, + { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204, upload-time = "2025-03-07T01:49:43.612Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d7/34f02dad2e30c31b10a51f6b04e025e5dd60e5f936af9045a9b858a05383/nvidia_nvjitlink_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:bd93fbeeee850917903583587f4fc3a4eafa022e34572251368238ab5e6bd67f", size = 268553710, upload-time = "2025-03-07T01:56:24.13Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161, upload-time = "2025-03-07T01:42:23.922Z" }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/9f/99/4c9c0c329bf9fc125008c3b54c7c94c0023518d06fc025ae36431375e1fe/nvidia_nvtx_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:619c8304aedc69f02ea82dd244541a83c3d9d40993381b3b590f1adaed3db41e", size = 56492, upload-time = "2025-03-07T01:52:24.69Z" }, +] + +[[package]] +name = "oauth2client" +version = "4.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httplib2" }, + { name = "pyasn1" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/7b/17244b1083e8e604bf154cf9b716aecd6388acd656dd01893d0d244c94d9/oauth2client-4.1.3.tar.gz", hash = "sha256:d486741e451287f69568a4d26d70d9acd73a2bbfa275746c535b4209891cccc6", size = 155910, upload-time = "2018-09-07T21:38:18.036Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/a9/4f25a14d23f0786b64875b91784607c2277eff25d48f915e39ff0cff505a/oauth2client-4.1.3-py2.py3-none-any.whl", hash = "sha256:b8a81cc5d60e2d364f0b1b98f958dbd472887acaf1a5b05e21c28c31a2d6d3ac", size = 98206, upload-time = "2018-09-07T21:38:16.742Z" }, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, +] + +[[package]] +name = "objsize" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/92/0c/4b759e274c2b11f1c44232d3bde33c5f8faf746226c7acd6b637c5b53d23/objsize-0.7.1.tar.gz", hash = "sha256:91e68d2a3031efb61b0e8cb7f995ddaeb65fe5ace9e737785e029f0932c2e619", size = 16428, upload-time = "2025-01-19T02:02:03.502Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/a7/55f8f3853a4a654d3a6fbf63e646e0b469b52c174703a10db70a1cb06c7e/objsize-0.7.1-py3-none-any.whl", hash = "sha256:634a0c134c4b1ff2c340fe29caf58bc0a16cb2ff7c556df609d04f026fdf4eca", size = 11351, upload-time = "2025-01-19T02:02:01.543Z" }, +] + +[[package]] +name = "omegaconf" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "antlr4-python3-runtime" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/48/6388f1bb9da707110532cb70ec4d2822858ddfb44f1cdf1233c20a80ea4b/omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7", size = 3298120, upload-time = "2022-12-08T20:59:22.753Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/94/1843518e420fa3ed6919835845df698c7e27e183cb997394e4a670973a65/omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b", size = 79500, upload-time = "2022-12-08T20:59:19.686Z" }, +] + +[[package]] +name = "opentelemetry-api" +version = "1.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/fc/b7564cbef36601aef0d6c9bc01f7badb64be8e862c2e1c3c5c3b43b53e4f/opentelemetry_api-1.41.1.tar.gz", hash = "sha256:0ad1814d73b875f84494387dae86ce0b12c68556331ce6ce8fe789197c949621", size = 71416, upload-time = "2026-04-24T13:15:38.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/59/3e7118ed140f76b0982ba4321bdaed1997a0473f9720de2d10788a577033/opentelemetry_api-1.41.1-py3-none-any.whl", hash = "sha256:a22df900e75c76dc08440710e51f52f1aa6b451b429298896023e60db5b3139f", size = 69007, upload-time = "2026-04-24T13:15:15.662Z" }, +] + +[[package]] +name = "opentelemetry-resourcedetector-gcp" +version = "1.11.0a0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-sdk" }, + { name = "requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/5d/2b3240d914b87b6dd9cd5ca2ef1ccaf1d0626b897d4c06877e22c8c10fcf/opentelemetry_resourcedetector_gcp-1.11.0a0.tar.gz", hash = "sha256:915a1d6fd15daca9eedd3fc52b0f705375054f2ef140e2e7a6b4cca95a47cdb1", size = 18796, upload-time = "2025-11-04T19:32:16.59Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/6c/1e13fe142a7ca3dc6489167203a1209d32430cca12775e1df9c9a41c54b2/opentelemetry_resourcedetector_gcp-1.11.0a0-py3-none-any.whl", hash = "sha256:5d65a2a039b1d40c6f41421dbb08d5f441368275ac6de6e76a8fccd1f6acb67e", size = 18798, upload-time = "2025-11-04T19:32:10.915Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/d0/54ee30dab82fb0acda23d144502771ff76ef8728459c83c3e89ef9fb1825/opentelemetry_sdk-1.41.1.tar.gz", hash = "sha256:724b615e1215b5aeacda0abb8a6a8922c9a1853068948bd0bd225a56d0c792e6", size = 230180, upload-time = "2026-04-24T13:15:50.991Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/e7/a1420b698aad018e1cf60fdbaaccbe49021fb415e2a0d81c242f4c518f54/opentelemetry_sdk-1.41.1-py3-none-any.whl", hash = "sha256:edee379c126c1bce952b0c812b48fe8ff35b30df0eecf17e98afa4d598b7d85d", size = 180213, upload-time = "2026-04-24T13:15:33.767Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.62b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/de/911ac9e309052aca1b20b2d5549d3db45d1011e1a610e552c6ccdd1b64f8/opentelemetry_semantic_conventions-0.62b1.tar.gz", hash = "sha256:c5cc6e04a7f8c7cdd30be2ed81499fa4e75bfbd52c9cb70d40af1f9cd3619802", size = 145750, upload-time = "2026-04-24T13:15:52.236Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/a6/83dc2ab6fa397ee66fba04fe2e74bdf7be3b3870005359ceb7689103c058/opentelemetry_semantic_conventions-0.62b1-py3-none-any.whl", hash = "sha256:cf506938103d331fbb78eded0d9788095f7fd59016f2bda813c3324e5a74a93c", size = 231620, upload-time = "2026-04-24T13:15:35.454Z" }, +] + +[[package]] +name = "opt-einsum" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004, upload-time = "2024-09-26T14:33:24.483Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932, upload-time = "2024-09-26T14:33:23.039Z" }, +] + +[[package]] +name = "optree" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/63/7b078bc36d5a206c21b03565a818ede38ff0fbf014e92085ec467ef10adb/optree-0.19.0.tar.gz", hash = "sha256:bc1991a948590756409e76be4e29efd4a487a185056d35db6c67619c19ea27a1", size = 175199, upload-time = "2026-02-23T01:56:37.752Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5e/5967a15ed63d98717815a51265bd73fb5ec5a4ca9938c59be909ef12f66f/optree-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e245b03f4edc90971dcf01691775105084f433393e6ba19a6fd0f151d5f39b58", size = 408515, upload-time = "2026-02-23T01:54:50.888Z" }, + { url = "https://files.pythonhosted.org/packages/43/5b/4e062008bfd2f836079afec06dd9cba76a01010aaffa8eae0d1915fa0ef6/optree-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:304ebd0449ace6ab0c18489baea1163a915b9aeb43a8635c6373ec09767fa1ba", size = 378935, upload-time = "2026-02-23T01:54:52.372Z" }, + { url = "https://files.pythonhosted.org/packages/bf/da/67424dad1834ba4bfe1ca16c1ca754e5fd32d7f8e7a488a70346c1bf1160/optree-0.19.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48366b810f0d37e2fa7bcb758d2a3198d62f0a4a60ac7e14287768345a4a95a9", size = 400165, upload-time = "2026-02-23T01:54:53.579Z" }, + { url = "https://files.pythonhosted.org/packages/65/af/f49c516de0ca47ce6a7a8f74499e63ba0a07744eae78958a2e6de0902fd6/optree-0.19.0-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:b511556fdc5a558ccd65f841710e9103f120cb575735f87ddfa3728b4098e606", size = 460863, upload-time = "2026-02-23T01:54:55.718Z" }, + { url = "https://files.pythonhosted.org/packages/92/cb/01e0a0551d6934f1158a7f90f690b4a68c1a08ba519ea4ab113e4064e499/optree-0.19.0-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba4925025a47b12237ff8acdcf8b9e972e7f36acafb291373d4de318a4b1b12c", size = 459863, upload-time = "2026-02-23T01:54:57.045Z" }, + { url = "https://files.pythonhosted.org/packages/b2/65/16b9c07e894a51e807404855e717e7e8221ce55f7fec3df46e9dc67c378c/optree-0.19.0-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a8d873ae944fb7d11797bb2ea2666379e78a4608e918d69a4c97fef4779f7da4", size = 459552, upload-time = "2026-02-23T01:54:58.159Z" }, + { url = "https://files.pythonhosted.org/packages/c3/34/3c9e11011c73457dc00e031713df6822eb0690cb849f479796073e070a56/optree-0.19.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6437d23f2708fe0fcdba9d3d75a1b82022caf2c15248059b8bf7e563422fb71", size = 441096, upload-time = "2026-02-23T01:54:59.536Z" }, + { url = "https://files.pythonhosted.org/packages/9c/39/0932e49b76fc3354a9c39c8bb57b04661e83b28fa6c74be09b520d98915b/optree-0.19.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:c2e01d07b2368f25932d5c6071d270a1d4db9e6cb2014eaafeded3d4c73ee406", size = 404747, upload-time = "2026-02-23T01:55:00.591Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d4/11ba9195b65bd77f8955bad5aca8c5fbfb0b273e52c4e7b29b3416c587f0/optree-0.19.0-cp311-cp311-win32.whl", hash = "sha256:846d07372ebc2ca959e9660b28d7c59ae34a02aac2fb73d0f3ec3de79af2fcb0", size = 306775, upload-time = "2026-02-23T01:55:01.659Z" }, + { url = "https://files.pythonhosted.org/packages/d9/13/ee6a65060edde25517151eff8a9e1468e6fd65054fabd14a441161eeafd6/optree-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:29d757b394641703098e1f9a62203c46a5f5cfa260cb8546bd05c8a2cdaf8754", size = 331592, upload-time = "2026-02-23T01:55:03.089Z" }, + { url = "https://files.pythonhosted.org/packages/cf/5e/3a4a66d0ecee599b948d2ef17010fcb9c111c69753a3911e4301005169a8/optree-0.19.0-cp311-cp311-win_arm64.whl", hash = "sha256:fd425b501420b437d5e925708898fae927660fd433836ac282adb20d54561c63", size = 343392, upload-time = "2026-02-23T01:55:04.201Z" }, + { url = "https://files.pythonhosted.org/packages/83/88/a31c2b7ee12f2c7a24a8d57aeecbbcd4c513152212aa1958fff736900033/optree-0.19.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2806e7baafc3c2985b71a5202fe3bde75838c7f09c0df0aa43a2e7ae12e65587", size = 411712, upload-time = "2026-02-23T01:56:31.829Z" }, + { url = "https://files.pythonhosted.org/packages/e7/db/33b61930bf2a879d9b114e63723ccf3965404d4fb5caffad5bee1a5be61c/optree-0.19.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:c39df2d664e3d54faaabfeda3ccfc4a768fc1314578b9ef741055387e13ef3bb", size = 384082, upload-time = "2026-02-23T01:56:32.962Z" }, + { url = "https://files.pythonhosted.org/packages/81/b1/64d04f0169feba3555434013ba2328019c2bde4d5d14600acfdcb91102a9/optree-0.19.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8bdb37b57863f18fad5601af4b94e8bc0ac145040b0ecbbc87f93d27fd6a676e", size = 403543, upload-time = "2026-02-23T01:56:33.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/cc9683a8c9eb54ba48739b7c394503d7df7a22b9f4bd2463ace46bbec593/optree-0.19.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b279f6d5e1cfe681b8bc8678529048081fe5ddaf49333a8bb13f3fb978dfdea", size = 444272, upload-time = "2026-02-23T01:56:35.453Z" }, + { url = "https://files.pythonhosted.org/packages/10/a7/9eb8b63ea378274517233ba0f2f0091a4cf38d92f91c9b1e6e646af31a8b/optree-0.19.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7bcb4e3e0b2b6db57e0882f0ba6b03a07d1489887e7e75d75c42b0e2be9f0019", size = 335393, upload-time = "2026-02-23T01:56:36.659Z" }, +] + +[[package]] +name = "orjson" +version = "3.11.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/1b/2024d06792d0779f9dbc51531b61c24f76c75b9f4ce05e6f3377a1814cea/orjson-3.11.8.tar.gz", hash = "sha256:96163d9cdc5a202703e9ad1b9ae757d5f0ca62f4fa0cc93d1f27b0e180cc404e", size = 5603832, upload-time = "2026-03-31T16:16:27.878Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/41/5aa7fa3b0f4dc6b47dcafc3cea909299c37e40e9972feabc8b6a74e2730d/orjson-3.11.8-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:003646067cc48b7fcab2ae0c562491c9b5d2cbd43f1e5f16d98fd118c5522d34", size = 229229, upload-time = "2026-03-31T16:14:50.424Z" }, + { url = "https://files.pythonhosted.org/packages/0a/d7/57e7f2458e0a2c41694f39fc830030a13053a84f837a5b73423dca1f0938/orjson-3.11.8-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:ed193ce51d77a3830cad399a529cd4ef029968761f43ddc549e1bc62b40d88f8", size = 128871, upload-time = "2026-03-31T16:14:51.888Z" }, + { url = "https://files.pythonhosted.org/packages/53/4a/e0fdb9430983e6c46e0299559275025075568aad5d21dd606faee3703924/orjson-3.11.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30491bc4f862aa15744b9738517454f1e46e56c972a2be87d70d727d5b2a8f8", size = 132104, upload-time = "2026-03-31T16:14:53.142Z" }, + { url = "https://files.pythonhosted.org/packages/08/4a/2025a60ff3f5c8522060cda46612d9b1efa653de66ed2908591d8d82f22d/orjson-3.11.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eda5b8b6be91d3f26efb7dc6e5e68ee805bc5617f65a328587b35255f138bf4", size = 130483, upload-time = "2026-03-31T16:14:54.605Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3c/b9cde05bdc7b2385c66014e0620627da638d3d04e4954416ab48c31196c5/orjson-3.11.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee8db7bfb6fe03581bbab54d7c4124a6dd6a7f4273a38f7267197890f094675f", size = 135481, upload-time = "2026-03-31T16:14:55.901Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f2/a8238e7734de7cb589fed319857a8025d509c89dc52fdcc88f39c6d03d5a/orjson-3.11.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d8b5231de76c528a46b57010bbd83fb51e056aa0220a372fd5065e978406f1c", size = 146819, upload-time = "2026-03-31T16:14:57.548Z" }, + { url = "https://files.pythonhosted.org/packages/db/10/dbf1e2a3cafea673b1b4350e371877b759060d6018a998643b7040e5de48/orjson-3.11.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58a4a208a6fbfdb7a7327b8f201c6014f189f721fd55d047cafc4157af1bc62a", size = 132846, upload-time = "2026-03-31T16:14:58.91Z" }, + { url = "https://files.pythonhosted.org/packages/f8/fc/55e667ec9c85694038fcff00573d221b085d50777368ee3d77f38668bf3c/orjson-3.11.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f8952d6d2505c003e8f0224ff7858d341fa4e33fef82b91c4ff0ef070f2393c", size = 133580, upload-time = "2026-03-31T16:15:00.519Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a6/c08c589a9aad0cb46c4831d17de212a2b6901f9d976814321ff8e69e8785/orjson-3.11.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0022bb50f90da04b009ce32c512dc1885910daa7cb10b7b0cba4505b16db82a8", size = 142042, upload-time = "2026-03-31T16:15:01.906Z" }, + { url = "https://files.pythonhosted.org/packages/5c/cc/2f78ea241d52b717d2efc38878615fe80425bf2beb6e68c984dde257a766/orjson-3.11.8-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ff51f9d657d1afb6f410cb435792ce4e1fe427aab23d2fcd727a2876e21d4cb6", size = 423845, upload-time = "2026-03-31T16:15:03.703Z" }, + { url = "https://files.pythonhosted.org/packages/70/07/c17dcf05dd8045457538428a983bf1f1127928df5bf328cb24d2b7cddacb/orjson-3.11.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6dbe9a97bdb4d8d9d5367b52a7c32549bba70b2739c58ef74a6964a6d05ae054", size = 147729, upload-time = "2026-03-31T16:15:05.203Z" }, + { url = "https://files.pythonhosted.org/packages/90/6c/0fb6e8a24e682e0958d71711ae6f39110e4b9cd8cab1357e2a89cb8e1951/orjson-3.11.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5c370674ebabe16c6ccac33ff80c62bf8a6e59439f5e9d40c1f5ab8fd2215b7", size = 136425, upload-time = "2026-03-31T16:15:07.052Z" }, + { url = "https://files.pythonhosted.org/packages/b2/35/4d3cc3a3d616035beb51b24a09bb872942dc452cf2df0c1d11ab35046d9f/orjson-3.11.8-cp311-cp311-win32.whl", hash = "sha256:0e32f7154299f42ae66f13488963269e5eccb8d588a65bc839ed986919fc9fac", size = 131870, upload-time = "2026-03-31T16:15:08.678Z" }, + { url = "https://files.pythonhosted.org/packages/13/26/9fe70f81d16b702f8c3a775e8731b50ad91d22dacd14c7599b60a0941cd1/orjson-3.11.8-cp311-cp311-win_amd64.whl", hash = "sha256:25e0c672a2e32348d2eb33057b41e754091f2835f87222e4675b796b92264f06", size = 127440, upload-time = "2026-03-31T16:15:09.994Z" }, + { url = "https://files.pythonhosted.org/packages/e8/c6/b038339f4145efd2859c1ca53097a52c0bb9cbdd24f947ebe146da1ad067/orjson-3.11.8-cp311-cp311-win_arm64.whl", hash = "sha256:9185589c1f2a944c17e26c9925dcdbc2df061cc4a145395c57f0c51f9b5dbfcd", size = 127399, upload-time = "2026-03-31T16:15:11.412Z" }, +] + +[[package]] +name = "overrides" +version = "7.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pandas" +version = "1.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/ee/146cab1ff6d575b54ace8a6a5994048380dc94879b0125b25e62edcb9e52/pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1", size = 5203060, upload-time = "2023-01-19T08:31:39.615Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/24/a26af514113fd5eca2d8fe41ba4f22f70dfe6afefde4a6beb6a203570935/pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc", size = 18387750, upload-time = "2023-01-19T08:29:43.119Z" }, + { url = "https://files.pythonhosted.org/packages/53/c9/d2f910dace7ef849b626980d0fd033b9cded36568949c8d560c9630ad2e0/pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d", size = 11868668, upload-time = "2023-01-19T08:29:48.733Z" }, + { url = "https://files.pythonhosted.org/packages/b0/be/1843b9aff84b98899663e7cad9f45513dfdd11d69cb5bd85c648aaf6a8d4/pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc", size = 10814036, upload-time = "2023-01-19T08:29:54.886Z" }, + { url = "https://files.pythonhosted.org/packages/63/8d/c2bd356b9d4baf1c5cf8d7e251fb4540e87083072c905430da48c2bb31eb/pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae", size = 11374218, upload-time = "2023-01-19T08:30:00.5Z" }, + { url = "https://files.pythonhosted.org/packages/56/73/3351beeb807dca69fcc3c4966bcccc51552bd01549a9b13c04ab00a43f21/pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6", size = 12017319, upload-time = "2023-01-19T08:30:06.097Z" }, + { url = "https://files.pythonhosted.org/packages/da/6d/1235da14daddaa6e47f74ba0c255358f0ce7a6ee05da8bf8eb49161aa6b5/pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003", size = 10303385, upload-time = "2023-01-19T08:30:11.148Z" }, +] + +[[package]] +name = "pandas-stubs" +version = "2.2.2.240807" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "types-pytz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/df/0da95bc75c76f1e012e0bc0b76da31faaf4254e94b9870f25e6311145e98/pandas_stubs-2.2.2.240807.tar.gz", hash = "sha256:64a559725a57a449f46225fbafc422520b7410bff9252b661a225b5559192a93", size = 103095, upload-time = "2024-08-07T12:30:54.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/f9/22c91632ea1b4c6165952f677bf9ad95f9ac36ffd7ef3e6450144e6d8b1a/pandas_stubs-2.2.2.240807-py3-none-any.whl", hash = "sha256:893919ad82be4275f0d07bb47a95d08bae580d3fdea308a7acfcb3f02e76186e", size = 157069, upload-time = "2024-08-07T12:30:51.868Z" }, +] + +[[package]] +name = "pandocfilters" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, +] + +[[package]] +name = "parameterized" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/49/00c0c0cc24ff4266025a53e41336b79adaa5a4ebfad214f433d623f9865e/parameterized-0.9.0.tar.gz", hash = "sha256:7fc905272cefa4f364c1a3429cbbe9c0f98b793988efb5bf90aac80f08db09b1", size = 24351, upload-time = "2023-03-27T02:01:11.592Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2f/804f58f0b856ab3bf21617cccf5b39206e6c4c94c2cd227bde125ea6105f/parameterized-0.9.0-py2.py3-none-any.whl", hash = "sha256:4e0758e3d41bea3bbd05ec14fc2c24736723f243b28d702081aef438c9372b1b", size = 20475, upload-time = "2023-03-27T02:01:09.31Z" }, +] + +[[package]] +name = "parso" +version = "0.8.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621, upload-time = "2026-02-09T15:45:24.425Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894, upload-time = "2026-02-09T15:45:21.391Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/17/9c3094b822982b9f1ea666d8580ce59000f61f87c1663556fb72031ad9ec/pathspec-1.1.0.tar.gz", hash = "sha256:f5d7c555da02fd8dde3e4a2354b6aba817a89112fa8f333f7917a2a4834dd080", size = 133918, upload-time = "2026-04-23T01:46:22.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/c9/8eed0486f074e9f1ca7f8ce5ad663e65f12fdab344028d658fa1b03d35e0/pathspec-1.1.0-py3-none-any.whl", hash = "sha256:574b128f7456bd899045ccd142dd446af7e6cfd0072d63ad73fbc55fbb4aaa42", size = 56264, upload-time = "2026-04-23T01:46:20.606Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "12.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, + { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, + { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, + { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, + { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, + { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, + { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, + { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, + { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, + { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, +] + +[[package]] +name = "pip" +version = "25.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.9.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, +] + +[[package]] +name = "portalocker" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/77/65b857a69ed876e1951e88aaba60f5ce6120c33703f7cb61a3c894b8c1b6/portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac", size = 95644, upload-time = "2025-06-14T13:20:40.03Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/a6/38c8e2f318bf67d338f4d629e93b0b4b9af331f455f0390ea8ce4a099b26/portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968", size = 22424, upload-time = "2025-06-14T13:20:38.083Z" }, +] + +[[package]] +name = "pre-commit" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/55/fccc69a49b66c54dcb9a7d8620131a2566db973837c6611b516a2d4e87d7/pre_commit-3.3.2.tar.gz", hash = "sha256:66e37bec2d882de1f17f88075047ef8962581f83c234ac08da21a0c58953d1f0", size = 176764, upload-time = "2023-05-17T22:37:41.385Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/30/c3d5d192b97de482b9adfa356724dfbb07e293b54d94c3b98dd2e5f24759/pre_commit-3.3.2-py2.py3-none-any.whl", hash = "sha256:8056bc52181efadf4aac792b1f4f255dfd2fb5a350ded7335d251a68561e8cb6", size = 202750, upload-time = "2023-05-17T22:37:39.397Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "proto-plus" +version = "1.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/0d/94dfe80193e79d55258345901acd2917523d56e8381bc4dee7fd38e3868a/proto_plus-1.27.2.tar.gz", hash = "sha256:b2adde53adadf75737c44d3dcb0104fde65250dfc83ad59168b4aa3e574b6a24", size = 57204, upload-time = "2026-03-26T22:18:57.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/f3/1fba73eeffafc998a25d59703b63f8be4fe8a5cb12eaff7386a0ba0f7125/proto_plus-1.27.2-py3-none-any.whl", hash = "sha256:6432f75893d3b9e70b9c412f1d2f03f65b11fb164b793d14ae2ca01821d22718", size = 50450, upload-time = "2026-03-26T22:13:42.927Z" }, +] + +[[package]] +name = "protobuf" +version = "4.25.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/8e/d08c41a8c004e1d437ef467e7c4f9c3295cd784eba48ed5d1d01f94b1dad/protobuf-4.25.9.tar.gz", hash = "sha256:b0dc7e7c68de8b1ce831dacb12fb407e838edbb8b6cc0dc3a2a6b4cbf6de9cff", size = 381040, upload-time = "2026-03-25T23:09:36.423Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/e9/59435bd04bdd46cb38c42a336b22f9843e8e586ff83c35a5423f8b14704e/protobuf-4.25.9-cp310-abi3-win32.whl", hash = "sha256:bde396f568b0b46fc8fbfe9f02facf25b6755b2578a3b8ac61e74b9d69499e03", size = 392879, upload-time = "2026-03-25T23:09:21.32Z" }, + { url = "https://files.pythonhosted.org/packages/f3/16/42a5c7f1001783d2b5bfcecde10127f09010f78982c86ae409122ce3ece6/protobuf-4.25.9-cp310-abi3-win_amd64.whl", hash = "sha256:3683c05154252206f7cb2d371626514b3708199d9bcf683b503dabf3a2e38e06", size = 413900, upload-time = "2026-03-25T23:09:23.589Z" }, + { url = "https://files.pythonhosted.org/packages/56/5b/0074a0a9eb01f3d1c4648ca5e81b22090c811b210b61df9018ac6d6c5cda/protobuf-4.25.9-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:9560813560e6ee72c11ca8873878bdb7ee003c96a57ebb013245fe84e2540904", size = 394826, upload-time = "2026-03-25T23:09:25.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/aa/b2dba856f64c36b2a06c67be1472de98cca07a2322d0f0cbf03279a40e5b/protobuf-4.25.9-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:999146ef02e7fa6a692477badd1528bcd7268df211852a3df2d834ba2b480791", size = 294191, upload-time = "2026-03-25T23:09:26.613Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5c/53f18822017b8bda6bd8bb4e02048e911fdc79a3dafdc83ab994fe922a84/protobuf-4.25.9-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:438c636de8fb706a0de94a12a268ef1ae8f5ba5ae655a7671fcda5968ba3c9be", size = 295178, upload-time = "2026-03-25T23:09:27.839Z" }, + { url = "https://files.pythonhosted.org/packages/16/28/d5065b212685875d3924bcdb3201cbf467cb4d58a18aa19a8dfd99ea80a9/protobuf-4.25.9-py3-none-any.whl", hash = "sha256:d49b615e7c935194ac161f0965699ac84df6112c378e05ec53da65d2e4cbb6d4", size = 156822, upload-time = "2026-03-25T23:09:34.957Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pyarrow" +version = "10.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/71/dd884e86aa92b2d602ee2064a485106ce5b447f8cae644f1a6f6a2e72016/pyarrow-10.0.1.tar.gz", hash = "sha256:1a14f57a5f472ce8234f2964cd5184cccaa8df7e04568c64edc33b23eb285dd5", size = 994148, upload-time = "2022-11-22T22:18:16.152Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/fe/4e2d2cd7e0d544018d7c7fee3dcee80303e16111605716592dd5333a2212/pyarrow-10.0.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:e3fe5049d2e9ca661d8e43fab6ad5a4c571af12d20a57dffc392a014caebef65", size = 24978297, upload-time = "2022-11-22T22:15:37.113Z" }, + { url = "https://files.pythonhosted.org/packages/1e/6e/915b7dfb7cfd2efd092b9b4d6579cb5848ba1dced3543bdd963df59ee2b5/pyarrow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:254017ca43c45c5098b7f2a00e995e1f8346b0fb0be225f042838323bb55283c", size = 22924198, upload-time = "2022-11-22T22:15:43.421Z" }, + { url = "https://files.pythonhosted.org/packages/ef/87/a0849cd20c75dd832683fdad0b321e6428281f3f3053e01c588269ae5b89/pyarrow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70acca1ece4322705652f48db65145b5028f2c01c7e426c5d16a30ba5d739c24", size = 33558654, upload-time = "2022-11-22T22:15:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/81/53/385279a985567a8a909bf9365cd15fc87c26ebe7db60a7220e4eeb407c87/pyarrow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb57334f2c57979a49b7be2792c31c23430ca02d24becd0b511cbe7b6b08649", size = 35844050, upload-time = "2022-11-22T22:15:59.425Z" }, + { url = "https://files.pythonhosted.org/packages/90/69/9e0ea39bed0d281e84cc3cd4a693ebc86266b705d910af9cc939e66c5d03/pyarrow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1765a18205eb1e02ccdedb66049b0ec148c2a0cb52ed1fb3aac322dfc086a6ee", size = 20195202, upload-time = "2022-11-22T22:16:19.133Z" }, +] + +[[package]] +name = "pyarrow-hotfix" +version = "0.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d2/ed/c3e8677f7abf3981838c2af7b5ac03e3589b3ef94fcb31d575426abae904/pyarrow_hotfix-0.7.tar.gz", hash = "sha256:59399cd58bdd978b2e42816a4183a55c6472d4e33d183351b6069f11ed42661d", size = 9910, upload-time = "2025-04-25T10:17:06.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/c3/94ade4906a2f88bc935772f59c934013b4205e773bcb4239db114a6da136/pyarrow_hotfix-0.7-py3-none-any.whl", hash = "sha256:3236f3b5f1260f0e2ac070a55c1a7b339c4bb7267839bd2015e283234e758100", size = 7923, upload-time = "2025-04-25T10:17:05.224Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + +[[package]] +name = "pybind11" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/f0/35145a3c3baffeef55d4b8324caa33abaa8fa56ab345ecd4b2211d09163e/pybind11-3.0.4.tar.gz", hash = "sha256:3286b59c8a774b9ee650169302dd5a4eedc30a8617905a0560dd8ee44775130c", size = 589533, upload-time = "2026-04-19T03:08:15.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/06/c3a23c9a0263b136c519f033a58d4641e73065fefc7754e9667ec206d992/pybind11-3.0.4-py3-none-any.whl", hash = "sha256:961720ee652da51d531b7b2451a6bd2bc042b0106e6d9baa48ecb7d58034ce63", size = 314166, upload-time = "2026-04-19T03:08:14.091Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/0a/fd7d723f8f8153418fb40cf9c940e82004fce7e987026b08a68a36dd3fe7/pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927", size = 471981, upload-time = "2026-04-20T14:46:41.402Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a2/1ba90a83e85a3f94c796b184f3efde9c72f2830dcda493eea8d59ba78e6d/pydantic_core-2.46.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ab124d49d0459b2373ecf54118a45c28a1e6d4192a533fbc915e70f556feb8e5", size = 2106740, upload-time = "2026-04-20T14:41:20.932Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f6/99ae893c89a0b9d3daec9f95487aa676709aa83f67643b3f0abaf4ab628a/pydantic_core-2.46.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cca67d52a5c7a16aed2b3999e719c4bcf644074eac304a5d3d62dd70ae7d4b2c", size = 1948293, upload-time = "2026-04-20T14:43:42.115Z" }, + { url = "https://files.pythonhosted.org/packages/3e/b8/2e8e636dc9e3f16c2e16bf0849e24be82c5ee82c603c65fc0326666328fc/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c024e08c0ba23e6fd68c771a521e9d6a792f2ebb0fa734296b36394dc30390e", size = 1973222, upload-time = "2026-04-20T14:41:57.841Z" }, + { url = "https://files.pythonhosted.org/packages/34/36/0e730beec4d83c5306f417afbd82ff237d9a21e83c5edf675f31ed84c1fe/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6645ce7eec4928e29a1e3b3d5c946621d105d3e79f0c9cddf07c2a9770949287", size = 2053852, upload-time = "2026-04-20T14:40:43.077Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f0/3071131f47e39136a17814576e0fada9168569f7f8c0e6ac4d1ede6a4958/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a712c7118e6c5ea96562f7b488435172abb94a3c53c22c9efc1412264a45cbbe", size = 2221134, upload-time = "2026-04-20T14:43:03.349Z" }, + { url = "https://files.pythonhosted.org/packages/2f/a9/a2dc023eec5aa4b02a467874bad32e2446957d2adcab14e107eab502e978/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a868ef3ff206343579021c40faf3b1edc64b1cc508ff243a28b0a514ccb050", size = 2279785, upload-time = "2026-04-20T14:41:19.285Z" }, + { url = "https://files.pythonhosted.org/packages/0a/44/93f489d16fb63fbd41c670441536541f6e8cfa1e5a69f40bc9c5d30d8c90/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7e8c32db809aa0f6ea1d6869ebc8518a65d5150fdfad8bcae6a49ae32a22e2", size = 2089404, upload-time = "2026-04-20T14:43:10.108Z" }, + { url = "https://files.pythonhosted.org/packages/2a/78/8692e3aa72b2d004f7a5d937f1dfdc8552ba26caf0bec75f342c40f00dec/pydantic_core-2.46.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3481bd1341dc85779ee506bc8e1196a277ace359d89d28588a9468c3ecbe63fa", size = 2114898, upload-time = "2026-04-20T14:44:51.475Z" }, + { url = "https://files.pythonhosted.org/packages/6a/62/e83133f2e7832532060175cebf1f13748f4c7e7e7165cdd1f611f174494b/pydantic_core-2.46.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8690eba565c6d68ffd3a8655525cbdd5246510b44a637ee2c6c03a7ebfe64d3c", size = 2157856, upload-time = "2026-04-20T14:43:46.64Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ec/6a500e3ad7718ee50583fae79c8651f5d37e3abce1fa9ae177ae65842c53/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4de88889d7e88d50d40ee5b39d5dac0bcaef9ba91f7e536ac064e6b2834ecccf", size = 2180168, upload-time = "2026-04-20T14:42:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/d8/53/8267811054b1aa7fc1dc7ded93812372ef79a839f5e23558136a6afbfde1/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:e480080975c1ef7f780b8f99ed72337e7cc5efea2e518a20a692e8e7b278eb8b", size = 2322885, upload-time = "2026-04-20T14:41:05.253Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c1/1c0acdb3aa0856ddc4ecc55214578f896f2de16f400cf51627eb3c26c1c4/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de3a5c376f8cd94da9a1b8fd3dd1c16c7a7b216ed31dc8ce9fd7a22bf13b836e", size = 2360328, upload-time = "2026-04-20T14:41:43.991Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/ef39cd0f4a926814f360e71c1adeab48ad214d9727e4deb48eedfb5bce1a/pydantic_core-2.46.3-cp311-cp311-win32.whl", hash = "sha256:fc331a5314ffddd5385b9ee9d0d2fee0b13c27e0e02dad71b1ae5d6561f51eeb", size = 1979464, upload-time = "2026-04-20T14:43:12.215Z" }, + { url = "https://files.pythonhosted.org/packages/18/9c/f41951b0d858e343f1cf09398b2a7b3014013799744f2c4a8ad6a3eec4f2/pydantic_core-2.46.3-cp311-cp311-win_amd64.whl", hash = "sha256:b5b9c6cf08a8a5e502698f5e153056d12c34b8fb30317e0c5fd06f45162a6346", size = 2070837, upload-time = "2026-04-20T14:41:47.707Z" }, + { url = "https://files.pythonhosted.org/packages/9f/1e/264a17cd582f6ed50950d4d03dd5fefd84e570e238afe1cb3e25cf238769/pydantic_core-2.46.3-cp311-cp311-win_arm64.whl", hash = "sha256:5dfd51cf457482f04ec49491811a2b8fd5b843b64b11eecd2d7a1ee596ea78a6", size = 2053647, upload-time = "2026-04-20T14:42:27.535Z" }, + { url = "https://files.pythonhosted.org/packages/66/7f/03dbad45cd3aa9083fbc93c210ae8b005af67e4136a14186950a747c6874/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:9715525891ed524a0a1eb6d053c74d4d4ad5017677fb00af0b7c2644a31bae46", size = 2105683, upload-time = "2026-04-20T14:42:19.779Z" }, + { url = "https://files.pythonhosted.org/packages/26/22/4dc186ac8ea6b257e9855031f51b62a9637beac4d68ac06bee02f046f836/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:9d2f400712a99a013aff420ef1eb9be077f8189a36c1e3ef87660b4e1088a874", size = 1940052, upload-time = "2026-04-20T14:43:59.274Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ca/d376391a5aff1f2e8188960d7873543608130a870961c2b6b5236627c116/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd2aab0e2e9dc2daf36bd2686c982535d5e7b1d930a1344a7bb6e82baab42a76", size = 1988172, upload-time = "2026-04-20T14:41:17.469Z" }, + { url = "https://files.pythonhosted.org/packages/0e/6b/523b9f85c23788755d6ab949329de692a2e3a584bc6beb67fef5e035aa9d/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9d76736da5f362fabfeea6a69b13b7f2be405c6d6966f06b2f6bfff7e64531", size = 2128596, upload-time = "2026-04-20T14:40:41.707Z" }, + { url = "https://files.pythonhosted.org/packages/1f/da/99d40830684f81dec901cac521b5b91c095394cc1084b9433393cde1c2df/pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:13afdd885f3d71280cf286b13b310ee0f7ccfefd1dbbb661514a474b726e2f25", size = 2107973, upload-time = "2026-04-20T14:42:06.175Z" }, + { url = "https://files.pythonhosted.org/packages/99/a5/87024121818d75bbb2a98ddbaf638e40e7a18b5e0f5492c9ca4b1b316107/pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f91c0aff3e3ee0928edd1232c57f643a7a003e6edf1860bc3afcdc749cb513f3", size = 1947191, upload-time = "2026-04-20T14:43:14.319Z" }, + { url = "https://files.pythonhosted.org/packages/60/62/0c1acfe10945b83a6a59d19fbaa92f48825381509e5701b855c08f13db76/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6529d1d128321a58d30afcc97b49e98836542f68dd41b33c2e972bb9e5290536", size = 2123791, upload-time = "2026-04-20T14:43:22.766Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/3b2393b4c8f44285561dc30b00cf307a56a2eff7c483a824db3b8221ca51/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:975c267cff4f7e7272eacbe50f6cc03ca9a3da4c4fbd66fffd89c94c1e311aa1", size = 2153197, upload-time = "2026-04-20T14:44:27.932Z" }, + { url = "https://files.pythonhosted.org/packages/ba/75/5af02fb35505051eee727c061f2881c555ab4f8ddb2d42da715a42c9731b/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2b8e4f2bbdf71415c544b4b1138b8060db7b6611bc927e8064c769f64bed651c", size = 2181073, upload-time = "2026-04-20T14:43:20.729Z" }, + { url = "https://files.pythonhosted.org/packages/10/92/7e0e1bd9ca3c68305db037560ca2876f89b2647deb2f8b6319005de37505/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e61ea8e9fff9606d09178f577ff8ccdd7206ff73d6552bcec18e1033c4254b85", size = 2315886, upload-time = "2026-04-20T14:44:04.826Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d8/101655f27eaf3e44558ead736b2795d12500598beed4683f279396fa186e/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b504bda01bafc69b6d3c7a0c7f039dcf60f47fab70e06fe23f57b5c75bdc82b8", size = 2360528, upload-time = "2026-04-20T14:40:47.431Z" }, + { url = "https://files.pythonhosted.org/packages/07/0f/1c34a74c8d07136f0d729ffe5e1fdab04fbdaa7684f61a92f92511a84a15/pydantic_core-2.46.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b00b76f7142fc60c762ce579bd29c8fa44aaa56592dd3c54fab3928d0d4ca6ff", size = 2184144, upload-time = "2026-04-20T14:42:57Z" }, +] + +[[package]] +name = "pydata-sphinx-theme" +version = "0.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "accessible-pygments" }, + { name = "babel" }, + { name = "beautifulsoup4" }, + { name = "docutils" }, + { name = "pygments" }, + { name = "sphinx" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/20/bb50f9de3a6de69e6abd6b087b52fa2418a0418b19597601605f855ad044/pydata_sphinx_theme-0.16.1.tar.gz", hash = "sha256:a08b7f0b7f70387219dc659bff0893a7554d5eb39b59d3b8ef37b8401b7642d7", size = 2412693, upload-time = "2024-12-17T10:53:39.537Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/0d/8ba33fa83a7dcde13eb3c1c2a0c1cc29950a048bfed6d9b0d8b6bd710b4c/pydata_sphinx_theme-0.16.1-py3-none-any.whl", hash = "sha256:225331e8ac4b32682c18fcac5a57a6f717c4e632cea5dd0e247b55155faeccde", size = 6723264, upload-time = "2024-12-17T10:53:35.645Z" }, +] + +[[package]] +name = "pydot" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/6e/916cdf94f9b38ae0777b254c75c3bdddee49a54cc4014aac1460a7a172b3/pydot-1.4.2.tar.gz", hash = "sha256:248081a39bcb56784deb018977e428605c1c758f10897a339fce1dd728ff007d", size = 137681, upload-time = "2021-02-15T15:43:08.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/76/75b1bb82e9bad3e3d656556eaa353d8cd17c4254393b08ec9786ac8ed273/pydot-1.4.2-py2.py3-none-any.whl", hash = "sha256:66c98190c65b8d2e2382a441b4c0edfdb4f4c025ef9cb9874de478fb0793a451", size = 21868, upload-time = "2021-02-15T15:43:06.74Z" }, +] + +[[package]] +name = "pyfarmhash" +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7f/256f1954343fc44641d04292e1410470337db3720bd57b510782e449d6db/pyfarmhash-0.3.2.tar.gz", hash = "sha256:4146308a0ed0b37d69003199c90fa59b155666c9deb0249b40e594cee10551ea", size = 99890, upload-time = "2021-12-31T08:23:27.642Z" } + +[[package]] +name = "pyg-lib" +version = "0.6.0+pt28cpu" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +resolution-markers = [ + "sys_platform != 'darwin'", +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.6.0%2Bpt28cpu-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.6.0%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "pyg-lib" +version = "0.6.0+pt28cu128" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.6.0%2Bpt28cu128-cp311-cp311-manylinux_2_28_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.6.0%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyjsparser" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/ef/c72abcfa2c6accd03e7c89c400790fc3d908c5804d50a7c4e9ceabd74d23/pyjsparser-2.7.1.tar.gz", hash = "sha256:be60da6b778cc5a5296a69d8e7d614f1f870faf94e1b1b6ac591f2ad5d729579", size = 24196, upload-time = "2019-04-21T21:56:17.708Z" } + +[[package]] +name = "pyjwt" +version = "2.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" }, +] + +[[package]] +name = "pymongo" +version = "4.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/64/50be6fbac9c79fe2e4c17401a467da2d8764d82833d83cec325afe5cab32/pymongo-4.17.0.tar.gz", hash = "sha256:70ffa08ba641468cc068cf46c06b34f01a8ce3489f6411309fcb5ceabe6b2fc0", size = 2523370, upload-time = "2026-04-20T16:39:53.524Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/e2/336d86f221cf1b56b2ed9330d4a3b98f9f38f0b37829ae9a9184617d5419/pymongo-4.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4141e6c6a339789b2974efa00ecd9409101672d77a0e3ee2cc3839eedf8ec4df", size = 874668, upload-time = "2026-04-20T16:37:41.39Z" }, + { url = "https://files.pythonhosted.org/packages/34/8e/75d3c6c935d187ab59c61e9c15d9aab3f274b563eaf1706e8cae5f508dec/pymongo-4.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e68c76b84e0c132d9dbf9307f12ff8185702328187a87b9aca8c941303873433", size = 875294, upload-time = "2026-04-20T16:37:43.432Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ec/62e855744489dbcd54fd778aae4d80fa4c4819e8fb228ca0cf6f21a03997/pymongo-4.17.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ba2195d4f386f839a52a23ea1cfd60ffaaba78a3d7841db51b7e433001139918", size = 1496233, upload-time = "2026-04-20T16:37:45.518Z" }, + { url = "https://files.pythonhosted.org/packages/82/e8/93e4e5e5ce8fdf8929dabeefe24aafa5ce046028eed0dfa8eeb936e72c49/pymongo-4.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8446ff4bfcb6ec2a2e50998c860986a1e992136f998b7f53e7a717fb8aa5a0b9", size = 1522927, upload-time = "2026-04-20T16:37:47.492Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ca/425dc1d21e0f17bdea0072fc463f662f7fa06d2852af52975c9eced3c07c/pymongo-4.17.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2a0d5ac205728c86e0a02192f1aa5f865b0d7d51f8df6101c01a69a7fc620d72", size = 1583468, upload-time = "2026-04-20T16:37:49.221Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9d/f08b07eeffda1a43c1759f0fa625e88ae12360996eb56d42aad832fa7dff/pymongo-4.17.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:485c8a8eaa4c739f00a331fc73757898ee7c092c214a79e63866ff76aaf282ff", size = 1572787, upload-time = "2026-04-20T16:37:51.061Z" }, + { url = "https://files.pythonhosted.org/packages/e9/c2/6855a07aafa7b894929af23675b6fb9634800ce43122b76a62f6eeb8da2a/pymongo-4.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b2dfcc795f5b9fedbe179a11fdf6051581479d196582a3fe819a92a00e9b9969", size = 1526184, upload-time = "2026-04-20T16:37:53.358Z" }, + { url = "https://files.pythonhosted.org/packages/4e/05/c952bac7db71c1942ea3559fcd308b49754cc5004b455935fb4000d1f37b/pymongo-4.17.0-cp311-cp311-win32.whl", hash = "sha256:c2292144505fb12156b981bd440f3dc994a883da06ac726c0c8692ccdbc1c510", size = 852621, upload-time = "2026-04-20T16:37:55.28Z" }, + { url = "https://files.pythonhosted.org/packages/11/c0/c04da9f4c0c6252404598f4e394b862a58a9e866822a70ae261c8a018fdf/pymongo-4.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:2e190827834fce70ecdf9d46796c6dbc0ce08ea87dc2ff5bc6f3f5579b605cb9", size = 867852, upload-time = "2026-04-20T16:37:57.233Z" }, + { url = "https://files.pythonhosted.org/packages/1d/b2/c7b4870fbeef471e947d3e014676f5910d02e0197074d692ebcf24ec049a/pymongo-4.17.0-cp311-cp311-win_arm64.whl", hash = "sha256:a8f9c40a09bb7d4b9fc8b1da65ecf6efa79bda5cb2756f39d9b6940fac1d19ae", size = 855019, upload-time = "2026-04-20T16:37:58.983Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pyre-extensions" +version = "0.0.32" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, + { name = "typing-inspect" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/53/5bc2532536e921c48366ad1047c1344ccef6afa5e84053f0f6e20a453767/pyre_extensions-0.0.32.tar.gz", hash = "sha256:5396715f14ea56c4d5fd0a88c57ca7e44faa468f905909edd7de4ad90ed85e55", size = 10852, upload-time = "2024-11-22T19:26:44.152Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/7a/9812cb8be9828ab688203c5ac5f743c60652887f0c00995a6f6f19f912bd/pyre_extensions-0.0.32-py3-none-any.whl", hash = "sha256:a63ba6883ab02f4b1a9f372ed4eb4a2f4c6f3d74879aa2725186fdfcfe3e5c68", size = 12766, upload-time = "2024-11-22T19:26:42.465Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-discovery" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", size = 58872, upload-time = "2026-04-07T17:28:49.249Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", size = 31894, upload-time = "2026-04-07T17:28:48.09Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + +[[package]] +name = "pytz" +version = "2026.1.post1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, +] + +[[package]] +name = "pyvers" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/32/99/23c73a1298b1c642d8ebdd78e1db4daf1e474152e6839df4f5c93357a3db/pyvers-0.2.2.tar.gz", hash = "sha256:205026bcd0b4c09198cb3a32f243fd179ef012882ce16d93dcb755320acd56f7", size = 12104, upload-time = "2026-01-23T14:12:07.619Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/bf/ea840f706b7824dd57220484465995309c8c217995ddb7ce4b262240e912/pyvers-0.2.2-py3-none-any.whl", hash = "sha256:c4696408a0b15fbaa90df33d3bc579cf23a74a73541858f5470216f12f51f3b1", size = 11569, upload-time = "2026-01-23T14:12:06.246Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, + { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, + { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/5d/305323ba86b284e6fcb0d842d6adaa2999035f70f8c38a9b6d21ad28c3d4/pyzmq-27.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:226b091818d461a3bef763805e75685e478ac17e9008f49fce2d3e52b3d58b86", size = 1333328, upload-time = "2025-09-08T23:07:45.946Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a0/fc7e78a23748ad5443ac3275943457e8452da67fda347e05260261108cbc/pyzmq-27.1.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0790a0161c281ca9723f804871b4027f2e8b5a528d357c8952d08cd1a9c15581", size = 908803, upload-time = "2025-09-08T23:07:47.551Z" }, + { url = "https://files.pythonhosted.org/packages/7e/22/37d15eb05f3bdfa4abea6f6d96eb3bb58585fbd3e4e0ded4e743bc650c97/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c895a6f35476b0c3a54e3eb6ccf41bf3018de937016e6e18748317f25d4e925f", size = 668836, upload-time = "2025-09-08T23:07:49.436Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c4/2a6fe5111a01005fc7af3878259ce17684fabb8852815eda6225620f3c59/pyzmq-27.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bbf8d3630bf96550b3be8e1fc0fea5cbdc8d5466c1192887bd94869da17a63e", size = 857038, upload-time = "2025-09-08T23:07:51.234Z" }, + { url = "https://files.pythonhosted.org/packages/cb/eb/bfdcb41d0db9cd233d6fb22dc131583774135505ada800ebf14dfb0a7c40/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15c8bd0fe0dabf808e2d7a681398c4e5ded70a551ab47482067a572c054c8e2e", size = 1657531, upload-time = "2025-09-08T23:07:52.795Z" }, + { url = "https://files.pythonhosted.org/packages/ab/21/e3180ca269ed4a0de5c34417dfe71a8ae80421198be83ee619a8a485b0c7/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bafcb3dd171b4ae9f19ee6380dfc71ce0390fefaf26b504c0e5f628d7c8c54f2", size = 2034786, upload-time = "2025-09-08T23:07:55.047Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b1/5e21d0b517434b7f33588ff76c177c5a167858cc38ef740608898cd329f2/pyzmq-27.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e829529fcaa09937189178115c49c504e69289abd39967cd8a4c215761373394", size = 1894220, upload-time = "2025-09-08T23:07:57.172Z" }, + { url = "https://files.pythonhosted.org/packages/03/f2/44913a6ff6941905efc24a1acf3d3cb6146b636c546c7406c38c49c403d4/pyzmq-27.1.0-cp311-cp311-win32.whl", hash = "sha256:6df079c47d5902af6db298ec92151db82ecb557af663098b92f2508c398bb54f", size = 567155, upload-time = "2025-09-08T23:07:59.05Z" }, + { url = "https://files.pythonhosted.org/packages/23/6d/d8d92a0eb270a925c9b4dd039c0b4dc10abc2fcbc48331788824ef113935/pyzmq-27.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:190cbf120fbc0fc4957b56866830def56628934a9d112aec0e2507aa6a032b97", size = 633428, upload-time = "2025-09-08T23:08:00.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/14/01afebc96c5abbbd713ecfc7469cfb1bc801c819a74ed5c9fad9a48801cb/pyzmq-27.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:eca6b47df11a132d1745eb3b5b5e557a7dae2c303277aa0e69c6ba91b8736e07", size = 559497, upload-time = "2025-09-08T23:08:02.15Z" }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/4c/c6/c4dcdecdbaa70969ee1fdced6d7b8f60cfabe64d25361f27ac4665a70620/pyzmq-27.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:18770c8d3563715387139060d37859c02ce40718d1faf299abddcdcc6a649066", size = 836265, upload-time = "2025-09-08T23:09:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/3e/79/f38c92eeaeb03a2ccc2ba9866f0439593bb08c5e3b714ac1d553e5c96e25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ac25465d42f92e990f8d8b0546b01c391ad431c3bf447683fdc40565941d0604", size = 800208, upload-time = "2025-09-08T23:09:51.073Z" }, + { url = "https://files.pythonhosted.org/packages/49/0e/3f0d0d335c6b3abb9b7b723776d0b21fa7f3a6c819a0db6097059aada160/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53b40f8ae006f2734ee7608d59ed661419f087521edbfc2149c3932e9c14808c", size = 567747, upload-time = "2025-09-08T23:09:52.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cf/f2b3784d536250ffd4be70e049f3b60981235d70c6e8ce7e3ef21e1adb25/pyzmq-27.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f605d884e7c8be8fe1aa94e0a783bf3f591b84c24e4bc4f3e7564c82ac25e271", size = 747371, upload-time = "2025-09-08T23:09:54.563Z" }, + { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, +] + +[[package]] +name = "redis" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-timeout", marker = "python_full_version < '3.11.3' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pyjwt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/cf/128b1b6d7086200c9f387bd4be9b2572a30b90745ef078bd8b235042dc9f/redis-5.3.1.tar.gz", hash = "sha256:ca49577a531ea64039b5a36db3d6cd1a0c7a60c34124d46924a45b956e8cf14c", size = 4626200, upload-time = "2025-07-25T08:06:27.778Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl", hash = "sha256:dc1909bd24669cc31b5f67a039700b16ec30571096c5f1f0d9d2324bff31af97", size = 272833, upload-time = "2025-07-25T08:06:26.317Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "regex" +version = "2026.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/3a246dbf05666918bd3664d9d787f84a9108f6f43cc953a077e4a7dfdb7e/regex-2026.4.4.tar.gz", hash = "sha256:e08270659717f6973523ce3afbafa53515c4dc5dcad637dc215b6fd50f689423", size = 416000, upload-time = "2026-04-03T20:56:28.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/7a/617356cbecdb452812a5d42f720d6d5096b360d4a4c1073af700ea140ad2/regex-2026.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4c36a85b00fadb85db9d9e90144af0a980e1a3d2ef9cd0f8a5bef88054657c6", size = 489415, upload-time = "2026-04-03T20:53:11.645Z" }, + { url = "https://files.pythonhosted.org/packages/20/e6/bf057227144d02e3ba758b66649e87531d744dda5f3254f48660f18ae9d8/regex-2026.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dcb5453ecf9cd58b562967badd1edbf092b0588a3af9e32ee3d05c985077ce87", size = 291205, upload-time = "2026-04-03T20:53:13.289Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3b/637181b787dd1a820ba1c712cee2b4144cd84a32dc776ca067b12b2d70c8/regex-2026.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6aa809ed4dc3706cc38594d67e641601bd2f36d5555b2780ff074edfcb136cf8", size = 289225, upload-time = "2026-04-03T20:53:16.002Z" }, + { url = "https://files.pythonhosted.org/packages/05/21/bac05d806ed02cd4b39d9c8e5b5f9a2998c94c3a351b7792e80671fa5315/regex-2026.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33424f5188a7db12958246a54f59a435b6cb62c5cf9c8d71f7cc49475a5fdada", size = 792434, upload-time = "2026-04-03T20:53:17.414Z" }, + { url = "https://files.pythonhosted.org/packages/d9/17/c65d1d8ae90b772d5758eb4014e1e011bb2db353fc4455432e6cc9100df7/regex-2026.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d346fccdde28abba117cc9edc696b9518c3307fbfcb689e549d9b5979018c6d", size = 861730, upload-time = "2026-04-03T20:53:18.903Z" }, + { url = "https://files.pythonhosted.org/packages/ad/64/933321aa082a2c6ee2785f22776143ba89840189c20d3b6b1d12b6aae16b/regex-2026.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:415a994b536440f5011aa77e50a4274d15da3245e876e5c7f19da349caaedd87", size = 906495, upload-time = "2026-04-03T20:53:20.561Z" }, + { url = "https://files.pythonhosted.org/packages/01/ea/4c8d306e9c36ac22417336b1e02e7b358152c34dc379673f2d331143725f/regex-2026.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21e5eb86179b4c67b5759d452ea7c48eb135cd93308e7a260aa489ed2eb423a4", size = 799810, upload-time = "2026-04-03T20:53:22.961Z" }, + { url = "https://files.pythonhosted.org/packages/29/ce/7605048f00e1379eba89d610c7d644d8f695dc9b26d3b6ecfa3132b872ff/regex-2026.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:312ec9dd1ae7d96abd8c5a36a552b2139931914407d26fba723f9e53c8186f86", size = 774242, upload-time = "2026-04-03T20:53:25.015Z" }, + { url = "https://files.pythonhosted.org/packages/e9/77/283e0d5023fde22cd9e86190d6d9beb21590a452b195ffe00274de470691/regex-2026.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0d2b28aa1354c7cd7f71b7658c4326f7facac106edd7f40eda984424229fd59", size = 781257, upload-time = "2026-04-03T20:53:26.918Z" }, + { url = "https://files.pythonhosted.org/packages/8b/fb/7f3b772be101373c8626ed34c5d727dcbb8abd42a7b1219bc25fd9a3cc04/regex-2026.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:349d7310eddff40429a099c08d995c6d4a4bfaf3ff40bd3b5e5cb5a5a3c7d453", size = 854490, upload-time = "2026-04-03T20:53:29.065Z" }, + { url = "https://files.pythonhosted.org/packages/85/30/56547b80f34f4dd2986e1cdd63b1712932f63b6c4ce2f79c50a6cd79d1c2/regex-2026.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e7ab63e9fe45a9ec3417509e18116b367e89c9ceb6219222a3396fa30b147f80", size = 763544, upload-time = "2026-04-03T20:53:30.917Z" }, + { url = "https://files.pythonhosted.org/packages/ac/2f/ce060fdfea8eff34a8997603532e44cdb7d1f35e3bc253612a8707a90538/regex-2026.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fe896e07a5a2462308297e515c0054e9ec2dd18dfdc9427b19900b37dfe6f40b", size = 844442, upload-time = "2026-04-03T20:53:32.463Z" }, + { url = "https://files.pythonhosted.org/packages/e5/44/810cb113096a1dacbe82789fbfab2823f79d19b7f1271acecb7009ba9b88/regex-2026.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb59c65069498dbae3c0ef07bbe224e1eaa079825a437fb47a479f0af11f774f", size = 789162, upload-time = "2026-04-03T20:53:34.039Z" }, + { url = "https://files.pythonhosted.org/packages/20/96/9647dd7f2ecf6d9ce1fb04dfdb66910d094e10d8fe53e9c15096d8aa0bd2/regex-2026.4.4-cp311-cp311-win32.whl", hash = "sha256:2a5d273181b560ef8397c8825f2b9d57013de744da9e8257b8467e5da8599351", size = 266227, upload-time = "2026-04-03T20:53:35.601Z" }, + { url = "https://files.pythonhosted.org/packages/33/80/74e13262460530c3097ff343a17de9a34d040a5dc4de9cf3a8241faab51c/regex-2026.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:9542ccc1e689e752594309444081582f7be2fdb2df75acafea8a075108566735", size = 278399, upload-time = "2026-04-03T20:53:37.021Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3c/39f19f47f19dcefa3403f09d13562ca1c0fd07ab54db2bc03148f3f6b46a/regex-2026.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:b5f9fb784824a042be3455b53d0b112655686fdb7a91f88f095f3fee1e2a2a54", size = 270473, upload-time = "2026-04-03T20:53:38.633Z" }, +] + +[[package]] +name = "requests" +version = "2.33.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, +] + +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "oauthlib" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, + { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, + { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, + { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, + { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, + { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, + { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, + { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, + { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, + { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, + { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, + { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, + { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, + { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, + { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, + { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, + { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, + { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, + { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, + { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, + { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, + { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, + { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, + { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, + { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, + { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, + { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, + { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, + { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, + { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, + { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, +] + +[[package]] +name = "scikit-build-core" +version = "0.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pathspec" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/cd/9ebb50029b6d8a3ee9e38cdce514ebd70190ec1edf28ab0a1f66d0b84670/scikit_build_core-0.12.2.tar.gz", hash = "sha256:562e0bbc9de1a354c87825ccf732080268d6582a0200f648e8c4a2dcb1e3736d", size = 303553, upload-time = "2026-03-05T18:25:57.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/49/b2f0fbe3165d55c02e7f9eec6a10685d518af0ef6e919ff2f589c2d15c85/scikit_build_core-0.12.2-py3-none-any.whl", hash = "sha256:6ea4730da400f9a998ec3287bd3ebc1d751fe45ad0a93451bead8618adbc02b1", size = 192625, upload-time = "2026-03-05T18:25:56.207Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/92/53ea2181da8ac6bf27170191028aee7251f8f841f8d3edbfdcaf2008fde9/scikit_learn-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:146b4d36f800c013d267b29168813f7a03a43ecd2895d04861f1240b564421da", size = 8595835, upload-time = "2025-12-10T07:07:39.385Z" }, + { url = "https://files.pythonhosted.org/packages/01/18/d154dc1638803adf987910cdd07097d9c526663a55666a97c124d09fb96a/scikit_learn-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f984ca4b14914e6b4094c5d52a32ea16b49832c03bd17a110f004db3c223e8e1", size = 8080381, upload-time = "2025-12-10T07:07:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/44/226142fcb7b7101e64fdee5f49dbe6288d4c7af8abf593237b70fca080a4/scikit_learn-1.8.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e30adb87f0cc81c7690a84f7932dd66be5bac57cfe16b91cb9151683a4a2d3b", size = 8799632, upload-time = "2025-12-10T07:07:43.899Z" }, + { url = "https://files.pythonhosted.org/packages/36/4d/4a67f30778a45d542bbea5db2dbfa1e9e100bf9ba64aefe34215ba9f11f6/scikit_learn-1.8.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ada8121bcb4dac28d930febc791a69f7cb1673c8495e5eee274190b73a4559c1", size = 9103788, upload-time = "2025-12-10T07:07:45.982Z" }, + { url = "https://files.pythonhosted.org/packages/89/3c/45c352094cfa60050bcbb967b1faf246b22e93cb459f2f907b600f2ceda5/scikit_learn-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:c57b1b610bd1f40ba43970e11ce62821c2e6569e4d74023db19c6b26f246cb3b", size = 8081706, upload-time = "2025-12-10T07:07:48.111Z" }, + { url = "https://files.pythonhosted.org/packages/3d/46/5416595bb395757f754feb20c3d776553a386b661658fb21b7c814e89efe/scikit_learn-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:2838551e011a64e3053ad7618dda9310175f7515f1742fa2d756f7c874c05961", size = 7688451, upload-time = "2025-12-10T07:07:49.873Z" }, +] + +[[package]] +name = "scipy" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, + { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, + { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, + { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, + { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, + { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, + { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, +] + +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, +] + +[[package]] +name = "sphinx" +version = "7.4.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911, upload-time = "2024-07-20T14:46:56.059Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624, upload-time = "2024-07-20T14:46:52.142Z" }, +] + +[[package]] +name = "sphinx-autoapi" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "astroid" }, + { name = "jinja2" }, + { name = "pyyaml" }, + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7f/a8/22b379a2a75ccb881217d3d4ae56d7d35f2d1bb4c8c0c51d0253676746a1/sphinx_autoapi-3.6.0.tar.gz", hash = "sha256:c685f274e41d0842ae7e199460c322c4bd7fec816ccc2da8d806094b4f64af06", size = 55417, upload-time = "2025-02-18T01:50:55.241Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/17/0eda9dc80fcaf257222b506844207e71b5d59567c41bbdcca2a72da119b9/sphinx_autoapi-3.6.0-py3-none-any.whl", hash = "sha256:f3b66714493cab140b0e896d33ce7137654a16ac1edb6563edcbd47bf975f711", size = 35281, upload-time = "2025-02-18T01:50:52.789Z" }, +] + +[[package]] +name = "sphinx-autodoc-typehints" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/cd/03e7b917230dc057922130a79ba0240df1693bfd76727ea33fae84b39138/sphinx_autodoc_typehints-2.3.0.tar.gz", hash = "sha256:535c78ed2d6a1bad393ba9f3dfa2602cf424e2631ee207263e07874c38fde084", size = 40709, upload-time = "2024-08-29T16:25:48.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f3/e0a4ce49da4b6f4e4ce84b3c39a0677831884cb9d8a87ccbf1e9e56e53ac/sphinx_autodoc_typehints-2.3.0-py3-none-any.whl", hash = "sha256:3098e2c6d0ba99eacd013eb06861acc9b51c6e595be86ab05c08ee5506ac0c67", size = 19836, upload-time = "2024-08-29T16:25:46.707Z" }, +] + +[[package]] +name = "sphinx-copybutton" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, +] + +[[package]] +name = "sphinx-design" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/2b/fdcfecad13079cc5c620b9ed380dc4b29f02cff69a1189057da0909e25ef/sphinx_design-0.6.0.tar.gz", hash = "sha256:ec8e3c5c59fed4049b3a5a2e209360feab31829346b5f6a0c7c342b894082192", size = 2193531, upload-time = "2024-05-22T23:12:19.628Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/e6/b0a74746e5fe33ed541ab2b67fc94bda6a604c66e92eda0e53cd29a6eab3/sphinx_design-0.6.0-py3-none-any.whl", hash = "sha256:e9bd07eecec82eb07ff72cb50fc3624e186b04f5661270bc7b62db86c7546e95", size = 2215316, upload-time = "2024-05-22T23:12:17.223Z" }, +] + +[[package]] +name = "sphinx-hoverxref" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, + { name = "sphinxcontrib-jquery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/93/180ade869c9d6a16ea58faaf4a130e3e61813baa04184fa56b6649cd5475/sphinx-hoverxref-1.3.0.tar.gz", hash = "sha256:e517dab4cb8186da58d78c53781459ee1116ec9c8413580c7dc43e124c5f3177", size = 1716338, upload-time = "2022-10-25T12:06:23.621Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/fa/1b860e4662906c7f7276a84d361b4ecdb2404adb39610b1673f82cf51b03/sphinx_hoverxref-1.3.0-py2.py3-none-any.whl", hash = "sha256:1064e4b1da49422873de555d79dc544da1556820fee05ab56f39d36cc86ba6ad", size = 32453, upload-time = "2022-10-25T12:06:19.137Z" }, +] + +[[package]] +name = "sphinx-rtd-theme" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "sphinx" }, + { name = "sphinxcontrib-jquery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/33/2a35a9cdbfda9086bda11457bcc872173ab3565b16b6d7f6b3efaa6dc3d6/sphinx_rtd_theme-2.0.0.tar.gz", hash = "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b", size = 2785005, upload-time = "2023-11-28T04:14:03.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/46/00fda84467815c29951a9c91e3ae7503c409ddad04373e7cfc78daad4300/sphinx_rtd_theme-2.0.0-py2.py3-none-any.whl", hash = "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586", size = 2824721, upload-time = "2023-11-28T04:13:59.589Z" }, +] + +[[package]] +name = "sphinx-tabs" +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "pygments" }, + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/32/ab475e252dc2b704e82a91141fa404cdd8901a5cf34958fd22afacebfccd/sphinx-tabs-3.4.5.tar.gz", hash = "sha256:ba9d0c1e3e37aaadd4b5678449eb08176770e0fc227e769b6ce747df3ceea531", size = 16070, upload-time = "2024-01-21T12:13:39.392Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/9f/4ac7dbb9f23a2ff5a10903a4f9e9f43e0ff051f63a313e989c962526e305/sphinx_tabs-3.4.5-py3-none-any.whl", hash = "sha256:92cc9473e2ecf1828ca3f6617d0efc0aa8acb06b08c56ba29d1413f2f0f6cf09", size = 9904, upload-time = "2024-01-21T12:13:37.67Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.49" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/b5/e3617cc67420f8f403efebd7b043128f94775e57e5b84e7255203390ceae/sqlalchemy-2.0.49-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5070135e1b7409c4161133aa525419b0062088ed77c92b1da95366ec5cbebbe", size = 2159126, upload-time = "2026-04-03T16:50:13.242Z" }, + { url = "https://files.pythonhosted.org/packages/20/9b/91ca80403b17cd389622a642699e5f6564096b698e7cdcbcbb6409898bc4/sqlalchemy-2.0.49-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ac7a3e245fd0310fd31495eb61af772e637bdf7d88ee81e7f10a3f271bff014", size = 3315509, upload-time = "2026-04-03T16:54:49.332Z" }, + { url = "https://files.pythonhosted.org/packages/b1/61/0722511d98c54de95acb327824cb759e8653789af2b1944ab1cc69d32565/sqlalchemy-2.0.49-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d4e5a0ceba319942fa6b585cf82539288a61e314ef006c1209f734551ab9536", size = 3315014, upload-time = "2026-04-03T16:56:56.376Z" }, + { url = "https://files.pythonhosted.org/packages/46/55/d514a653ffeb4cebf4b54c47bec32ee28ad89d39fafba16eeed1d81dccd5/sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ddcb27fb39171de36e207600116ac9dfd4ae46f86c82a9bf3934043e80ebb88", size = 3267388, upload-time = "2026-04-03T16:54:51.272Z" }, + { url = "https://files.pythonhosted.org/packages/2f/16/0dcc56cb6d3335c1671a2258f5d2cb8267c9a2260e27fde53cbfb1b3540a/sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:32fe6a41ad97302db2931f05bb91abbcc65b5ce4c675cd44b972428dd2947700", size = 3289602, upload-time = "2026-04-03T16:56:57.63Z" }, + { url = "https://files.pythonhosted.org/packages/51/6c/f8ab6fb04470a133cd80608db40aa292e6bae5f162c3a3d4ab19544a67af/sqlalchemy-2.0.49-cp311-cp311-win32.whl", hash = "sha256:46d51518d53edfbe0563662c96954dc8fcace9832332b914375f45a99b77cc9a", size = 2119044, upload-time = "2026-04-03T17:00:53.455Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/55a6d627d04b6ebb290693681d7683c7da001eddf90b60cfcc41ee907978/sqlalchemy-2.0.49-cp311-cp311-win_amd64.whl", hash = "sha256:951d4a210744813be63019f3df343bf233b7432aadf0db54c75802247330d3af", size = 2143642, upload-time = "2026-04-03T17:00:54.769Z" }, + { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "tabulate" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, +] + +[[package]] +name = "tenacity" +version = "9.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, +] + +[[package]] +name = "tensorboard" +version = "2.16.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "grpcio" }, + { name = "markdown" }, + { name = "numpy" }, + { name = "protobuf" }, + { name = "setuptools" }, + { name = "six" }, + { name = "tensorboard-data-server" }, + { name = "werkzeug" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/d0/b97889ffa769e2d1fdebb632084d5e8b53fc299d43a537acee7ec0c021a3/tensorboard-2.16.2-py3-none-any.whl", hash = "sha256:9f2b4e7dad86667615c0e5cd072f1ea8403fc032a299f0072d6f74855775cc45", size = 5490335, upload-time = "2024-02-16T19:56:55.912Z" }, +] + +[[package]] +name = "tensorboard-data-server" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl", hash = "sha256:7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb", size = 2356, upload-time = "2023-10-23T21:23:32.16Z" }, + { url = "https://files.pythonhosted.org/packages/b7/85/dabeaf902892922777492e1d253bb7e1264cadce3cea932f7ff599e53fea/tensorboard_data_server-0.7.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9fe5d24221b29625dbc7328b0436ca7fc1c23de4acf4d272f1180856e32f9f60", size = 4823598, upload-time = "2023-10-23T21:23:33.714Z" }, + { url = "https://files.pythonhosted.org/packages/73/c6/825dab04195756cf8ff2e12698f22513b3db2f64925bdd41671bfb33aaa5/tensorboard_data_server-0.7.2-py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:ef687163c24185ae9754ed5650eb5bc4d84ff257aabdc33f0cc6f74d8ba54530", size = 6590363, upload-time = "2023-10-23T21:23:35.583Z" }, +] + +[[package]] +name = "tensordict" +version = "0.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cloudpickle" }, + { name = "importlib-metadata" }, + { name = "numpy" }, + { name = "orjson" }, + { name = "packaging" }, + { name = "pyvers" }, + { name = "torch", version = "2.8.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/83/e3a4726d83d7ad4d3f5d56b1e00473dfa550ed73411b9f3fa1a039c8c56f/tensordict-0.12.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ae8c58dd32aacdd73ab13b021f6e00bee6c58cfb896936e11603c834e801c465", size = 888476, upload-time = "2026-04-20T15:11:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/04/4f/ffb8514f584ad9f4cff40582929818b41a2fe810413183466b71cd784abe/tensordict-0.12.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:76bb01f9f0580bf0ca1210f7f6d4ef8d8bc4a4bf2458adbad4443c65191eedab", size = 531915, upload-time = "2026-04-20T15:11:24.094Z" }, + { url = "https://files.pythonhosted.org/packages/05/b7/78f7eada33d84c1de7bc632b159c4b9e468fc245d1bcf36e1d7e8ec98581/tensordict-0.12.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:3b43e6ce47a23c87335087ef862bd11d996161edc0ab7b8f08796fee297668e0", size = 536398, upload-time = "2026-04-20T15:11:25.494Z" }, + { url = "https://files.pythonhosted.org/packages/48/5f/0a2cfec89d0273632e70880f341427a25558666bf9e0a5c8e637fe95e3cc/tensordict-0.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae42ba5511d76698c1da2461805f9a6d6c2cfacd318289385bd841ed404edf3d", size = 584735, upload-time = "2026-04-20T15:11:26.995Z" }, +] + +[[package]] +name = "tensorflow" +version = "2.16.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "astunparse" }, + { name = "flatbuffers" }, + { name = "gast" }, + { name = "google-pasta" }, + { name = "grpcio" }, + { name = "h5py" }, + { name = "keras" }, + { name = "libclang" }, + { name = "ml-dtypes" }, + { name = "numpy" }, + { name = "opt-einsum" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "six" }, + { name = "tensorboard" }, + { name = "tensorflow-io-gcs-filesystem" }, + { name = "termcolor" }, + { name = "typing-extensions" }, + { name = "wrapt" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/69/9999c2d9e8a3b08dfcfc7e9259a05fb1da5f700936091d2eb4a7985c2776/tensorflow-2.16.2-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:ec06570d57bfa0e2be804405e3cdc2960e94887e7619ffb6bc053e9775b695aa", size = 259588062, upload-time = "2024-06-28T18:51:09.316Z" }, + { url = "https://files.pythonhosted.org/packages/9d/72/6f09443493b9df2fd8a9585c9af4d9453762906a8e5735a8a5efa6e3d1e3/tensorflow-2.16.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:2c8a0e79395639b762e62002db99b2f6cc608f744312c9940899c1128f325331", size = 227025342, upload-time = "2024-06-28T18:51:19.421Z" }, + { url = "https://files.pythonhosted.org/packages/b5/01/c03e98c8e97d151d9ce075fae210f838832eb53d8aa55669d384cb72925b/tensorflow-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8728b12bc86941d90d0a927c40d4b21f8820964a80439a7c45f850eb37d57067", size = 218904025, upload-time = "2024-06-28T18:51:29.52Z" }, + { url = "https://files.pythonhosted.org/packages/43/dd/8f03331107b76e63313d2089ddfbd13f15e51fb8ed73517cdd0ab3341928/tensorflow-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8798dea8e2281b4a0b569d9c00e7949c0090509be363da271e1ef21828bffae", size = 590660880, upload-time = "2024-06-28T18:51:42.788Z" }, + { url = "https://files.pythonhosted.org/packages/1f/97/dec9dfa95cfbee631adffbeb0b7eda51ddc93a5f7e8aa8f4d95dde59e69e/tensorflow-2.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:1da04e39834cdba509b4dd5ac5c71c3a1d1ffe6bc03e6970e65791b9a4071340", size = 2070, upload-time = "2024-06-28T18:51:55.409Z" }, +] + +[[package]] +name = "tensorflow-data-validation" +version = "1.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "apache-beam", extra = ["gcp"] }, + { name = "joblib" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "protobuf" }, + { name = "pyarrow" }, + { name = "pyfarmhash" }, + { name = "six" }, + { name = "tensorflow" }, + { name = "tensorflow-metadata" }, + { name = "tfx-bsl" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/d8/8b193132c8769d31d11e92b058cd6651b5d8cba1b91878665bdb7408260b/tensorflow_data_validation-1.16.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:b21fa86c61da5cee81b4d602953fea16878de4874eb6035bf7f3221cfeb91559", size = 20236896, upload-time = "2024-10-15T20:20:03.396Z" }, + { url = "https://files.pythonhosted.org/packages/da/4d/4e758f700f1e1b0162ff74c0dca0f0ebd8e366e57088a29ec1f3bdaf0287/tensorflow_data_validation-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2e666e724a418fb45cca17442d33f906e91c086ad4a897aaf4473c94e0f4ee", size = 18961461, upload-time = "2024-10-15T20:40:56.17Z" }, +] + +[[package]] +name = "tensorflow-io-gcs-filesystem" +version = "0.37.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/9b/b2fb82d0da673b17a334f785fc19c23483165019ddc33b275ef25ca31173/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:32c50ab4e29a23c1f91cd0f9ab8c381a0ab10f45ef5c5252e94965916041737c", size = 2470224, upload-time = "2024-07-01T23:44:23.039Z" }, + { url = "https://files.pythonhosted.org/packages/5b/cc/16634e76f3647fbec18187258da3ba11184a6232dcf9073dc44579076d36/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b02f9c5f94fd62773954a04f69b68c4d576d076fd0db4ca25d5479f0fbfcdbad", size = 3479613, upload-time = "2024-07-01T23:44:24.399Z" }, + { url = "https://files.pythonhosted.org/packages/de/bf/ba597d3884c77d05a78050f3c178933d69e3f80200a261df6eaa920656cd/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e1f2796b57e799a8ca1b75bf47c2aaa437c968408cc1a402a9862929e104cda", size = 4842079, upload-time = "2024-07-01T23:44:26.825Z" }, + { url = "https://files.pythonhosted.org/packages/66/7f/e36ae148c2f03d61ca1bff24bc13a0fef6d6825c966abef73fc6f880a23b/tensorflow_io_gcs_filesystem-0.37.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee7c8ee5fe2fd8cb6392669ef16e71841133041fee8a330eff519ad9b36e4556", size = 5085736, upload-time = "2024-07-01T23:44:28.618Z" }, +] + +[[package]] +name = "tensorflow-metadata" +version = "1.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "googleapis-common-protos" }, + { name = "protobuf" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/57/393aa9dde72347cde9e01f665bac344f14adefd5c748be45b23aa5804f6d/tensorflow_metadata-1.16.1-py3-none-any.whl", hash = "sha256:2ce72ea31d78a00c0c74c6d465482335aa5cb2a3b2a104dedba0b258bc7bb18a", size = 28984, upload-time = "2024-10-09T19:57:12.683Z" }, +] + +[[package]] +name = "tensorflow-serving-api" +version = "2.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "grpcio" }, + { name = "protobuf" }, + { name = "tensorflow" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/6a/6e91fbca9593663edc368df59a5d57e5549048530ba42c6833b560e30cba/tensorflow_serving_api-2.16.1-py2.py3-none-any.whl", hash = "sha256:13f859ea45055d393acd4cd8b44283ac52ff2970051fb9b96a69e0a626f07992", size = 26539, upload-time = "2024-03-22T02:01:06.207Z" }, +] + +[[package]] +name = "tensorflow-transform" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "apache-beam", extra = ["gcp"] }, + { name = "numpy" }, + { name = "protobuf" }, + { name = "pyarrow" }, + { name = "pydot" }, + { name = "tensorflow" }, + { name = "tensorflow-metadata" }, + { name = "tf-keras" }, + { name = "tfx-bsl" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/a4/7610ef37f429855bd832f98377715298f66478c8e16174e9330f10bd1eed/tensorflow_transform-1.16.0-py3-none-any.whl", hash = "sha256:a2138d6c052cb5ad30ca08191d8795d2059e86d6001b2cb5a3b00d567727d7f1", size = 451456, upload-time = "2024-10-28T22:32:45.384Z" }, +] + +[[package]] +name = "termcolor" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, +] + +[[package]] +name = "tf-keras" +version = "2.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tensorflow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/63/59a4aee62ea8999850e4b3b5d94b60fe280ca93de60d0e2958066e24d6a7/tf_keras-2.16.0.tar.gz", hash = "sha256:db53891f1ac98197c2acced98cdca8c06ba8255655a6cb7eb95ed49676118280", size = 1259784, upload-time = "2024-03-09T02:28:18.742Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/aa/cf09f8956d4f276f655b13674e15d8d6015fd832f9689aa9ff2a515781ab/tf_keras-2.16.0-py3-none-any.whl", hash = "sha256:b2ad0541fa7d9e92c4b7a1b96593377afb58aaff374299a6ca6be1a42f51d899", size = 1724695, upload-time = "2024-03-09T02:28:15.99Z" }, +] + +[[package]] +name = "tfx-bsl" +version = "1.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "apache-beam", extra = ["gcp"] }, + { name = "google-api-python-client" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "protobuf" }, + { name = "pyarrow" }, + { name = "tensorflow" }, + { name = "tensorflow-metadata" }, + { name = "tensorflow-serving-api" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/e5/a123d09e160be09423544529883f59b89dcbfb3242218a535af2b23826f4/tfx_bsl-1.16.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:1c13ff8f4de36ceea598a5a06b9cccabb73c7b9792ca280b915abd24b6a141b5", size = 24141870, upload-time = "2024-10-14T19:08:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/c0/e7/b5f7858a63884248bc58f9ecf4d2d41d1eca66103ac742a8b6bb6ec6a075/tfx_bsl-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc767ff141f5f6b0b21ef0a0479f8294a678c0340f8f9b7e69413fb429e329a6", size = 22546327, upload-time = "2024-10-14T19:22:45.563Z" }, +] + +[[package]] +name = "threadpoolctl" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, +] + +[[package]] +name = "tinycss2" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, +] + +[[package]] +name = "torch" +version = "2.8.0" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "platform_machine == 'arm64' and sys_platform == 'darwin'", +] +dependencies = [ + { name = "filelock", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "fsspec", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "jinja2", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "networkx", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "sympy", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] +wheels = [ + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:3d05017d19bc99741288e458888283a44b0ee881d53f05f72f8b1cfea8998122", upload-time = "2025-10-01T23:35:48Z" }, +] + +[[package]] +name = "torch" +version = "2.8.0+cpu" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "sys_platform != 'darwin'", + "platform_machine != 'arm64' and sys_platform == 'darwin'", +] +dependencies = [ + { name = "filelock", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "fsspec", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "jinja2", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "networkx", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "sympy", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-extensions", marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] +wheels = [ + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-linux_s390x.whl", hash = "sha256:2bfc013dd6efdc8f8223a0241d3529af9f315dffefb53ffa3bf14d3f10127da6", upload-time = "2025-10-01T23:33:07Z" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:680129efdeeec3db5da3f88ee5d28c1b1e103b774aef40f9d638e2cce8f8d8d8", upload-time = "2025-10-01T23:33:11Z" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cb06175284673a581dd91fb1965662ae4ecaba6e5c357aa0ea7bb8b84b6b7eeb", upload-time = "2025-10-01T23:33:14Z" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_amd64.whl", hash = "sha256:7631ef49fbd38d382909525b83696dc12a55d68492ade4ace3883c62b9fc140f", upload-time = "2025-10-01T23:33:20Z" }, + { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-win_arm64.whl", hash = "sha256:41e6fc5ec0914fcdce44ccf338b1d19a441b55cafdd741fd0bf1af3f9e4cfd14", upload-time = "2025-10-01T23:33:36Z" }, +] + +[[package]] +name = "torch" +version = "2.8.0+cu128" +source = { registry = "https://download.pytorch.org/whl/cu128" } +dependencies = [ + { name = "filelock", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "fsspec", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "jinja2", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "networkx", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cuda-cupti-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cuda-runtime-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cudnn-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cufft-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cufile-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-curand-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cusolver-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cusparse-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-cusparselt-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-nccl-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "nvidia-nvtx-cu12", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "sympy", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, + { name = "triton", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (platform_machine != 'x86_64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'linux' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-extensions", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +wheels = [ + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:039b9dcdd6bdbaa10a8a5cd6be22c4cb3e3589a341e5f904cbb571ca28f55bed", upload-time = "2025-10-01T23:49:06Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-win_amd64.whl", hash = "sha256:34c55443aafd31046a7963b63d30bc3b628ee4a704f826796c865fdfd05bb596", upload-time = "2025-10-01T23:49:30Z" }, +] + +[[package]] +name = "torch-cluster" +version = "1.6.3" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +dependencies = [ + { name = "scipy", marker = "sys_platform == 'darwin'" }, +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3-cp311-cp311-macosx_10_9_universal2.whl" }, +] + +[[package]] +name = "torch-cluster" +version = "1.6.3+pt28cpu" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +resolution-markers = [ + "sys_platform != 'darwin'", +] +dependencies = [ + { name = "scipy", marker = "sys_platform != 'darwin'" }, +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torch-cluster" +version = "1.6.3+pt28cu128" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } +dependencies = [ + { name = "scipy" }, +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_cluster-1.6.3%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_cluster-1.6.3%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torch-geometric" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "numpy" }, + { name = "psutil" }, + { name = "pyparsing" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/75/63/b210152635902da7fe79fcdd16517fae108f457a0ed22c737e702a9afbae/torch_geometric-2.7.0.tar.gz", hash = "sha256:f9099e4aece1a9f618c84dbaac33a77f43139736698c7e8bddf3301ef1f2e8d4", size = 876725, upload-time = "2025-10-15T20:48:03.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/4dffd7300500465e0b4a2ae917dcb2ce771de0b9a772670365799a27c024/torch_geometric-2.7.0-py3-none-any.whl", hash = "sha256:6e0cd3ad824d484651ef5d308fc66c687bfcf5ba040d56d1e0fe0f81f365e292", size = 1275346, upload-time = "2025-10-15T20:48:01.949Z" }, +] + +[[package]] +name = "torch-scatter" +version = "2.1.2" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2-cp311-cp311-macosx_10_9_universal2.whl" }, +] + +[[package]] +name = "torch-scatter" +version = "2.1.2+pt28cpu" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +resolution-markers = [ + "sys_platform != 'darwin'", +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torch-scatter" +version = "2.1.2+pt28cu128" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_scatter-2.1.2%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_scatter-2.1.2%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torch-sparse" +version = "0.6.18" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +dependencies = [ + { name = "scipy", marker = "sys_platform == 'darwin'" }, +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18-cp311-cp311-macosx_11_0_universal2.whl" }, +] + +[[package]] +name = "torch-sparse" +version = "0.6.18+pt28cpu" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +resolution-markers = [ + "sys_platform != 'darwin'", +] +dependencies = [ + { name = "scipy", marker = "sys_platform != 'darwin'" }, +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torch-sparse" +version = "0.6.18+pt28cu128" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } +dependencies = [ + { name = "scipy" }, +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_sparse-0.6.18%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_sparse-0.6.18%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torch-spline-conv" +version = "1.2.2" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2-cp311-cp311-macosx_10_9_universal2.whl" }, +] + +[[package]] +name = "torch-spline-conv" +version = "1.2.2+pt28cpu" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } +resolution-markers = [ + "sys_platform != 'darwin'", +] +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2%2Bpt28cpu-cp311-cp311-linux_aarch64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torch-spline-conv" +version = "1.2.2+pt28cu128" +source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } +wheels = [ + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_spline_conv-1.2.2%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_spline_conv-1.2.2%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, +] + +[[package]] +name = "torchmetrics" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lightning-utilities" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "torch", version = "2.8.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/01/b6c344ac04b53ebe3759ba938f1406775fe7649c44ba2e27e467be4e6fe9/torchmetrics-1.0.3.tar.gz", hash = "sha256:1c20ea2f0db434334e88da6c015ddf936d43379bfb403e9dc2a7272b0eab453c", size = 432173, upload-time = "2023-08-08T15:50:49.966Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/90/9ac94af10cd1777859a92be1e8186325490654930e871f8bb219cc342868/torchmetrics-1.0.3-py3-none-any.whl", hash = "sha256:612a74ab8ebfcd4ebb38e5c370ce29a0e73af074948048f6f2233e25cf60da75", size = 731638, upload-time = "2023-08-08T15:50:47.799Z" }, +] + +[[package]] +name = "torchrec" +version = "1.5.0+cpu" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "sys_platform != 'darwin'", +] +dependencies = [ + { name = "fbgemm-gpu", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" } }, + { name = "iopath" }, + { name = "pyre-extensions" }, + { name = "tensordict" }, + { name = "torchmetrics" }, + { name = "tqdm" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/cpu/torchrec-1.5.0%2Bcpu-py3-none-any.whl", hash = "sha256:0625095099a0b0b9edd8c7777b8a83fe5e2ed9c67529e0fb6bf1b71d2d7f392f", upload-time = "2026-02-16T15:11:21Z" }, +] + +[[package]] +name = "torchrec" +version = "1.5.0+cu128" +source = { registry = "https://download.pytorch.org/whl/cu128" } +dependencies = [ + { name = "fbgemm-gpu", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } }, + { name = "iopath" }, + { name = "pyre-extensions" }, + { name = "tensordict" }, + { name = "torchmetrics" }, + { name = "tqdm" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/cu128/torchrec-1.5.0%2Bcu128-py3-none-any.whl", hash = "sha256:966421c469f4c3cad5d3800e6f4f49fcfcc33e14a39801c465f00f335efc4e75", upload-time = "2026-02-16T15:11:35Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" }, + { url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" }, + { url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" }, + { url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" }, + { url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" }, + { url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" }, + { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "triton" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools", marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/39/43325b3b651d50187e591eefa22e236b2981afcebaefd4f2fc0ea99df191/triton-3.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b70f5e6a41e52e48cfc087436c8a28c17ff98db369447bcaff3b887a3ab4467", size = 155531138, upload-time = "2025-07-30T19:58:29.908Z" }, +] + +[[package]] +name = "types-protobuf" +version = "7.34.1.20260408" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/b1/4521e68c2cc17703d80eb42796751345376dd4c706f84007ef5e7c707774/types_protobuf-7.34.1.20260408.tar.gz", hash = "sha256:e2c0a0430e08c75b52671a6f0035abfdcc791aad12af16274282de1b721758ab", size = 68835, upload-time = "2026-04-08T04:26:43.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/b5/0bc9874d89c58fb0ce851e150055ce732d254dbb10b06becbc7635d0d635/types_protobuf-7.34.1.20260408-py3-none-any.whl", hash = "sha256:ebbcd4e27b145aef6a59bc0cb6c013b3528151c1ba5e7f7337aeee355d276a5e", size = 86012, upload-time = "2026-04-08T04:26:42.566Z" }, +] + +[[package]] +name = "types-psutil" +version = "7.0.0.20250401" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/fc/3829cb113aa05c268b18369f1f003a4589216931658ebfa69e3d4931ba60/types_psutil-7.0.0.20250401.tar.gz", hash = "sha256:2a7d663c0888a079fc1643ebc109ad12e57a21c9552a9e2035da504191336dbf", size = 20273, upload-time = "2025-04-01T03:06:48.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/42/45e01f3bce242c0caad36b968114a00f454169df6c771c092c96727239d8/types_psutil-7.0.0.20250401-py3-none-any.whl", hash = "sha256:ed23f7140368104afe4e05a6085a5fa56fbe8c880a0f4dfe8d63e041106071ed", size = 23173, upload-time = "2025-04-01T03:06:46.701Z" }, +] + +[[package]] +name = "types-pytz" +version = "2026.1.1.20260408" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/b7/33f5a4f29b1f285b99ff79a607751a7996194cbb98705e331dab7a2daa28/types_pytz-2026.1.1.20260408.tar.gz", hash = "sha256:89b6a34b9198ea2a4b98a9d15cbca987053f52a105fd44f7ce3789cae4349408", size = 10788, upload-time = "2026-04-08T04:28:14.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/90/12c059e6bb330a22d9cc97daf027ac7fb7f50fbf518e4d88185b4d39120e/types_pytz-2026.1.1.20260408-py3-none-any.whl", hash = "sha256:c7e4dec76221fb7d0c97b91ad8561d689bebe39b6bcb7b728387e7ffd8cde788", size = 10124, upload-time = "2026-04-08T04:28:13.353Z" }, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.20260408" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/73/b759b1e413c31034cc01ecdfb96b38115d0ab4db55a752a3929f0cd449fd/types_pyyaml-6.0.12.20260408.tar.gz", hash = "sha256:92a73f2b8d7f39ef392a38131f76b970f8c66e4c42b3125ae872b7c93b556307", size = 17735, upload-time = "2026-04-08T04:30:50.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/f0/c391068b86abb708882c6d75a08cd7d25b2c7227dab527b3a3685a3c635b/types_pyyaml-6.0.12.20260408-py3-none-any.whl", hash = "sha256:fbc42037d12159d9c801ebfcc79ebd28335a7c13b08a4cfbc6916df78fee9384", size = 20339, upload-time = "2026-04-08T04:30:50.113Z" }, +] + +[[package]] +name = "types-requests" +version = "2.31.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "types-urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f9/b8/c1e8d39996b4929b918aba10dba5de07a8b3f4c8487bb61bb79882544e69/types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0", size = 15535, upload-time = "2023-09-27T06:19:38.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/a1/6f8dc74d9069e790d604ddae70cb46dcbac668f1bb08136e7b0f2f5cd3bf/types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9", size = 14516, upload-time = "2023-09-27T06:19:36.373Z" }, +] + +[[package]] +name = "types-tqdm" +version = "4.67.0.20250513" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "types-requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/74/a77b5179e3543853c51ce786b300cd253934477c81aab4d786dff9894724/types_tqdm-4.67.0.20250513.tar.gz", hash = "sha256:907028c8d0a8fc20072132cd0cee72a3b6c72abf32f5ff914a7749e7d13b351e", size = 17207, upload-time = "2025-05-13T03:06:17.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/7b/996a534691afd516f60fa3ad3f4101b38f7222fff6c1b12f508a4c817695/types_tqdm-4.67.0.20250513-py3-none-any.whl", hash = "sha256:73d2bdac28bab49235d8660aece6c415636a0fb406f7a24b39737dfc6bf6a5dd", size = 24060, upload-time = "2025-05-13T03:06:16.241Z" }, +] + +[[package]] +name = "types-urllib3" +version = "1.26.25.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239, upload-time = "2023-07-20T15:19:31.307Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377, upload-time = "2023-07-20T15:19:30.379Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, +] + +[[package]] +name = "uritemplate" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/42/da/fa9aca2d866f932f17703b3b5edb7b17114bb261122b6e535ef0d9f618f8/uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae", size = 32806, upload-time = "2019-12-19T22:13:08.286Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/0c/60d82c077998feb631608dca3cc1fe19ac074e772bf0c24cf409b977b815/uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f", size = 15615, upload-time = "2019-12-19T22:13:06.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "virtualenv" +version = "21.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "python-discovery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0c/98/3a7e644e19cb26133488caff231be390579860bbbb3da35913c49a1d0a46/virtualenv-21.2.4.tar.gz", hash = "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada", size = 5850742, upload-time = "2026-04-14T22:15:31.438Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/8d/edd0bd910ff803c308ee9a6b7778621af0d10252219ad9f19ef4d4982a61/virtualenv-21.2.4-py3-none-any.whl", hash = "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac", size = 5831232, upload-time = "2026-04-14T22:15:29.342Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + +[[package]] +name = "websockets" +version = "16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, + { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, + { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, + { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, + { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, + { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, + { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, + { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, + { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, + { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, + { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, +] + +[[package]] +name = "werkzeug" +version = "3.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", size = 226459, upload-time = "2026-04-02T18:49:12.72Z" }, +] + +[[package]] +name = "wheel" +version = "0.47.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/62/75f18a0f03b4219c456652c7780e4d749b929eb605c098ce3a5b6b6bc081/wheel-0.47.0.tar.gz", hash = "sha256:cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3", size = 63854, upload-time = "2026-04-22T15:51:27.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl", hash = "sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced", size = 32218, upload-time = "2026-04-22T15:51:26.296Z" }, +] + +[[package]] +name = "wrapt" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/81/60c4471fce95afa5922ca09b88a25f03c93343f759aae0f31fb4412a85c7/wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb", size = 60666, upload-time = "2026-03-06T02:52:58.934Z" }, + { url = "https://files.pythonhosted.org/packages/6b/be/80e80e39e7cb90b006a0eaf11c73ac3a62bbfb3068469aec15cc0bc795de/wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d", size = 61601, upload-time = "2026-03-06T02:53:00.487Z" }, + { url = "https://files.pythonhosted.org/packages/b0/be/d7c88cd9293c859fc74b232abdc65a229bb953997995d6912fc85af18323/wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894", size = 114057, upload-time = "2026-03-06T02:52:44.08Z" }, + { url = "https://files.pythonhosted.org/packages/ea/25/36c04602831a4d685d45a93b3abea61eca7fe35dab6c842d6f5d570ef94a/wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842", size = 116099, upload-time = "2026-03-06T02:54:56.74Z" }, + { url = "https://files.pythonhosted.org/packages/5c/4e/98a6eb417ef551dc277bec1253d5246b25003cf36fdf3913b65cb7657a56/wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8", size = 112457, upload-time = "2026-03-06T02:53:52.842Z" }, + { url = "https://files.pythonhosted.org/packages/cb/a6/a6f7186a5297cad8ec53fd7578533b28f795fdf5372368c74bd7e6e9841c/wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6", size = 115351, upload-time = "2026-03-06T02:53:32.684Z" }, + { url = "https://files.pythonhosted.org/packages/97/6f/06e66189e721dbebd5cf20e138acc4d1150288ce118462f2fcbff92d38db/wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9", size = 111748, upload-time = "2026-03-06T02:53:08.455Z" }, + { url = "https://files.pythonhosted.org/packages/ef/43/4808b86f499a51370fbdbdfa6cb91e9b9169e762716456471b619fca7a70/wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15", size = 113783, upload-time = "2026-03-06T02:53:02.02Z" }, + { url = "https://files.pythonhosted.org/packages/91/2c/a3f28b8fa7ac2cefa01cfcaca3471f9b0460608d012b693998cd61ef43df/wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b", size = 57977, upload-time = "2026-03-06T02:53:27.844Z" }, + { url = "https://files.pythonhosted.org/packages/3f/c3/2b1c7bd07a27b1db885a2fab469b707bdd35bddf30a113b4917a7e2139d2/wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1", size = 60336, upload-time = "2026-03-06T02:54:28.104Z" }, + { url = "https://files.pythonhosted.org/packages/ec/5c/76ece7b401b088daa6503d6264dd80f9a727df3e6042802de9a223084ea2/wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a", size = 58756, upload-time = "2026-03-06T02:53:16.319Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, +] + +[[package]] +name = "xxhash" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, + { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, + { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, + { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, + { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, + { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, + { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, + { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, +] + +[[package]] +name = "yarl" +version = "1.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/aa/60da938b8f0997ba3a911263c40d82b6f645a67902a490b46f3355e10fae/yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99", size = 123641, upload-time = "2026-03-01T22:04:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/24/84/e237607faf4e099dbb8a4f511cfd5efcb5f75918baad200ff7380635631b/yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c", size = 86248, upload-time = "2026-03-01T22:04:44.757Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0d/71ceabc14c146ba8ee3804ca7b3d42b1664c8440439de5214d366fec7d3a/yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432", size = 85988, upload-time = "2026-03-01T22:04:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6c/4a90d59c572e46b270ca132aca66954f1175abd691f74c1ef4c6711828e2/yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", size = 100566, upload-time = "2026-03-01T22:04:47.639Z" }, + { url = "https://files.pythonhosted.org/packages/49/fb/c438fb5108047e629f6282a371e6e91cf3f97ee087c4fb748a1f32ceef55/yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", size = 92079, upload-time = "2026-03-01T22:04:48.925Z" }, + { url = "https://files.pythonhosted.org/packages/d9/13/d269aa1aed3e4f50a5a103f96327210cc5fa5dd2d50882778f13c7a14606/yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", size = 108741, upload-time = "2026-03-01T22:04:50.838Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/115b16f22c37ea4437d323e472945bea97301c8ec6089868fa560abab590/yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", size = 108099, upload-time = "2026-03-01T22:04:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", size = 102678, upload-time = "2026-03-01T22:04:55.176Z" }, + { url = "https://files.pythonhosted.org/packages/85/59/cd98e556fbb2bf8fab29c1a722f67ad45c5f3447cac798ab85620d1e70af/yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", size = 100803, upload-time = "2026-03-01T22:04:56.588Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c0/b39770b56d4a9f0bb5f77e2f1763cd2d75cc2f6c0131e3b4c360348fcd65/yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", size = 100163, upload-time = "2026-03-01T22:04:58.492Z" }, + { url = "https://files.pythonhosted.org/packages/e7/64/6980f99ab00e1f0ff67cb84766c93d595b067eed07439cfccfc8fb28c1a6/yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", size = 93859, upload-time = "2026-03-01T22:05:00.268Z" }, + { url = "https://files.pythonhosted.org/packages/38/69/912e6c5e146793e5d4b5fe39ff5b00f4d22463dfd5a162bec565ac757673/yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", size = 108202, upload-time = "2026-03-01T22:05:02.273Z" }, + { url = "https://files.pythonhosted.org/packages/59/97/35ca6767524687ad64e5f5c31ad54bc76d585585a9fcb40f649e7e82ffed/yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", size = 99866, upload-time = "2026-03-01T22:05:03.597Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1c/1a3387ee6d73589f6f2a220ae06f2984f6c20b40c734989b0a44f5987308/yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", size = 107852, upload-time = "2026-03-01T22:05:04.986Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/35c0750fcd5a3f781058bfd954515dd4b1eab45e218cbb85cf11132215f1/yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", size = 102919, upload-time = "2026-03-01T22:05:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1c/9a1979aec4a81896d597bcb2177827f2dbee3f5b7cc48b2d0dadb644b41d/yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5", size = 82602, upload-time = "2026-03-01T22:05:08.444Z" }, + { url = "https://files.pythonhosted.org/packages/93/22/b85eca6fa2ad9491af48c973e4c8cf6b103a73dbb271fe3346949449fca0/yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46", size = 87461, upload-time = "2026-03-01T22:05:10.145Z" }, + { url = "https://files.pythonhosted.org/packages/93/95/07e3553fe6f113e6864a20bdc53a78113cda3b9ced8784ee52a52c9f80d8/yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928", size = 82336, upload-time = "2026-03-01T22:05:11.554Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, +] From 50dc6207c0b529a9022a05e123afe4d56d6e0dcf Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 22:03:57 +0000 Subject: [PATCH 092/148] Update uv --- uv.lock | 1831 +++++++++++++++++++++++++------------------------------ 1 file changed, 839 insertions(+), 992 deletions(-) diff --git a/uv.lock b/uv.lock index af2435aba..baae02ddc 100644 --- a/uv.lock +++ b/uv.lock @@ -49,7 +49,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.13.5" +version = "3.13.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -60,25 +60,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994, upload-time = "2025-10-28T20:59:39.937Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/f5/a20c4ac64aeaef1679e25c9983573618ff765d7aa829fa2b84ae7573169e/aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6", size = 757513, upload-time = "2026-03-31T21:57:02.146Z" }, - { url = "https://files.pythonhosted.org/packages/75/0a/39fa6c6b179b53fcb3e4b3d2b6d6cad0180854eda17060c7218540102bef/aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d", size = 506748, upload-time = "2026-03-31T21:57:04.275Z" }, - { url = "https://files.pythonhosted.org/packages/87/ec/e38ce072e724fd7add6243613f8d1810da084f54175353d25ccf9f9c7e5a/aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c", size = 501673, upload-time = "2026-03-31T21:57:06.208Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/3bc7525d7e2beaa11b309a70d48b0d3cfc3c2089ec6a7d0820d59c657053/aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb", size = 1763757, upload-time = "2026-03-31T21:57:07.882Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ab/e87744cf18f1bd78263aba24924d4953b41086bd3a31d22452378e9028a0/aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6", size = 1720152, upload-time = "2026-03-31T21:57:09.946Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f3/ed17a6f2d742af17b50bae2d152315ed1b164b07a5fd5cc1754d99e4dfa5/aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13", size = 1818010, upload-time = "2026-03-31T21:57:12.157Z" }, - { url = "https://files.pythonhosted.org/packages/53/06/ecbc63dc937192e2a5cb46df4d3edb21deb8225535818802f210a6ea5816/aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174", size = 1907251, upload-time = "2026-03-31T21:57:14.023Z" }, - { url = "https://files.pythonhosted.org/packages/7e/a5/0521aa32c1ddf3aa1e71dcc466be0b7db2771907a13f18cddaa45967d97b/aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc", size = 1759969, upload-time = "2026-03-31T21:57:16.146Z" }, - { url = "https://files.pythonhosted.org/packages/f6/78/a38f8c9105199dd3b9706745865a8a59d0041b6be0ca0cc4b2ccf1bab374/aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6", size = 1616871, upload-time = "2026-03-31T21:57:17.856Z" }, - { url = "https://files.pythonhosted.org/packages/6f/41/27392a61ead8ab38072105c71aa44ff891e71653fe53d576a7067da2b4e8/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49", size = 1739844, upload-time = "2026-03-31T21:57:19.679Z" }, - { url = "https://files.pythonhosted.org/packages/6e/55/5564e7ae26d94f3214250009a0b1c65a0c6af4bf88924ccb6fdab901de28/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8", size = 1731969, upload-time = "2026-03-31T21:57:22.006Z" }, - { url = "https://files.pythonhosted.org/packages/6d/c5/705a3929149865fc941bcbdd1047b238e4a72bcb215a9b16b9d7a2e8d992/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d", size = 1795193, upload-time = "2026-03-31T21:57:24.256Z" }, - { url = "https://files.pythonhosted.org/packages/a6/19/edabed62f718d02cff7231ca0db4ef1c72504235bc467f7b67adb1679f48/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c", size = 1606477, upload-time = "2026-03-31T21:57:26.364Z" }, - { url = "https://files.pythonhosted.org/packages/de/fc/76f80ef008675637d88d0b21584596dc27410a990b0918cb1e5776545b5b/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac", size = 1813198, upload-time = "2026-03-31T21:57:28.316Z" }, - { url = "https://files.pythonhosted.org/packages/e5/67/5b3ac26b80adb20ea541c487f73730dc8fa107d632c998f25bbbab98fcda/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3", size = 1752321, upload-time = "2026-03-31T21:57:30.549Z" }, - { url = "https://files.pythonhosted.org/packages/88/06/e4a2e49255ea23fa4feeb5ab092d90240d927c15e47b5b5c48dff5a9ce29/aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06", size = 439069, upload-time = "2026-03-31T21:57:32.388Z" }, - { url = "https://files.pythonhosted.org/packages/c0/43/8c7163a596dab4f8be12c190cf467a1e07e4734cf90eebb39f7f5d53fc6a/aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8", size = 462859, upload-time = "2026-03-31T21:57:34.455Z" }, + { url = "https://files.pythonhosted.org/packages/35/74/b321e7d7ca762638cdf8cdeceb39755d9c745aff7a64c8789be96ddf6e96/aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0", size = 743409, upload-time = "2025-10-28T20:56:00.354Z" }, + { url = "https://files.pythonhosted.org/packages/99/3d/91524b905ec473beaf35158d17f82ef5a38033e5809fe8742e3657cdbb97/aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb", size = 497006, upload-time = "2025-10-28T20:56:01.85Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d3/7f68bc02a67716fe80f063e19adbd80a642e30682ce74071269e17d2dba1/aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9", size = 493195, upload-time = "2025-10-28T20:56:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/98/31/913f774a4708775433b7375c4f867d58ba58ead833af96c8af3621a0d243/aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613", size = 1747759, upload-time = "2025-10-28T20:56:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/e8/63/04efe156f4326f31c7c4a97144f82132c3bb21859b7bb84748d452ccc17c/aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead", size = 1704456, upload-time = "2025-10-28T20:56:06.986Z" }, + { url = "https://files.pythonhosted.org/packages/8e/02/4e16154d8e0a9cf4ae76f692941fd52543bbb148f02f098ca73cab9b1c1b/aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780", size = 1807572, upload-time = "2025-10-28T20:56:08.558Z" }, + { url = "https://files.pythonhosted.org/packages/34/58/b0583defb38689e7f06798f0285b1ffb3a6fb371f38363ce5fd772112724/aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a", size = 1895954, upload-time = "2025-10-28T20:56:10.545Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f3/083907ee3437425b4e376aa58b2c915eb1a33703ec0dc30040f7ae3368c6/aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592", size = 1747092, upload-time = "2025-10-28T20:56:12.118Z" }, + { url = "https://files.pythonhosted.org/packages/ac/61/98a47319b4e425cc134e05e5f3fc512bf9a04bf65aafd9fdcda5d57ec693/aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab", size = 1606815, upload-time = "2025-10-28T20:56:14.191Z" }, + { url = "https://files.pythonhosted.org/packages/97/4b/e78b854d82f66bb974189135d31fce265dee0f5344f64dd0d345158a5973/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30", size = 1723789, upload-time = "2025-10-28T20:56:16.101Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fc/9d2ccc794fc9b9acd1379d625c3a8c64a45508b5091c546dea273a41929e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40", size = 1718104, upload-time = "2025-10-28T20:56:17.655Z" }, + { url = "https://files.pythonhosted.org/packages/66/65/34564b8765ea5c7d79d23c9113135d1dd3609173da13084830f1507d56cf/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948", size = 1785584, upload-time = "2025-10-28T20:56:19.238Z" }, + { url = "https://files.pythonhosted.org/packages/30/be/f6a7a426e02fc82781afd62016417b3948e2207426d90a0e478790d1c8a4/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf", size = 1595126, upload-time = "2025-10-28T20:56:20.836Z" }, + { url = "https://files.pythonhosted.org/packages/e5/c7/8e22d5d28f94f67d2af496f14a83b3c155d915d1fe53d94b66d425ec5b42/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782", size = 1800665, upload-time = "2025-10-28T20:56:22.922Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/91133c8b68b1da9fc16555706aa7276fdf781ae2bb0876c838dd86b8116e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8", size = 1739532, upload-time = "2025-10-28T20:56:25.924Z" }, + { url = "https://files.pythonhosted.org/packages/17/6b/3747644d26a998774b21a616016620293ddefa4d63af6286f389aedac844/aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec", size = 431876, upload-time = "2025-10-28T20:56:27.524Z" }, + { url = "https://files.pythonhosted.org/packages/c3/63/688462108c1a00eb9f05765331c107f95ae86f6b197b865d29e930b7e462/aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c", size = 456205, upload-time = "2025-10-28T20:56:29.062Z" }, ] [[package]] @@ -120,15 +120,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d [[package]] name = "anyio" -version = "4.13.0" +version = "4.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, + { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, ] [[package]] @@ -210,15 +211,15 @@ wheels = [ [[package]] name = "argo-workflows" -version = "6.6.19" +version = "6.6.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/42/b1d178909d1b45899bc65fd44150645de007038f9ab6f389abd08257f484/argo_workflows-6.6.19.tar.gz", hash = "sha256:b4d18f4fe01501be71a6fee03921021a694caa96d13f78f6b4e1dce84fc0a545", size = 286753, upload-time = "2026-02-16T14:22:29.206Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/ed/011b97eca0ce38745c1c92f83c461097f6c0face0d53eb6a46dfc355cb0f/argo_workflows-6.6.12.tar.gz", hash = "sha256:3e268c896834eb9554dbb8bb865be66425ffbe5cb4d99a5fde47e13cb7718ab2", size = 286644, upload-time = "2025-10-14T10:33:45.423Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/99/fddc48bd238fe2465788f2fc63e18811f9db4d7e5fff74d75e406e05c558/argo_workflows-6.6.19-py3-none-any.whl", hash = "sha256:daa77916a2c6fcee328d5aa2c2f4a6f684f27269bf26e77dc2cc0f187b9c9c0b", size = 1262875, upload-time = "2026-02-16T14:22:27.28Z" }, + { url = "https://files.pythonhosted.org/packages/df/a3/90364d83c2544d267b4302489bb22b4f364cfa0f7ca61395bde58ee6c25e/argo_workflows-6.6.12-py3-none-any.whl", hash = "sha256:6bee34fab131692caf44bca93e2885cdb8e3592a54750a231091d05e634bb341", size = 1262778, upload-time = "2025-10-14T10:33:43.757Z" }, ] [[package]] @@ -232,11 +233,11 @@ wheels = [ [[package]] name = "asttokens" -version = "3.0.1" +version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, ] [[package]] @@ -263,33 +264,33 @@ wheels = [ [[package]] name = "attrs" -version = "26.1.0" +version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] [[package]] name = "babel" -version = "2.18.0" +version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] [[package]] name = "beautifulsoup4" -version = "4.14.3" +version = "4.14.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, + { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" }, ] [[package]] @@ -320,11 +321,11 @@ wheels = [ [[package]] name = "certifi" -version = "2026.4.22" +version = "2025.10.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" }, + { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, ] [[package]] @@ -353,63 +354,57 @@ wheels = [ [[package]] name = "cfgv" -version = "3.5.0" +version = "3.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, ] [[package]] name = "chardet" -version = "7.4.3" +version = "5.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/b6/9df434a8eeba2e6628c465a1dfa31034228ef79b26f76f46278f4ef7e49d/chardet-7.4.3.tar.gz", hash = "sha256:cc1d4eb92a4ec1c2df3b490836ffa46922e599d34ce0bb75cf41fd2bf6303d56", size = 784800, upload-time = "2026-04-13T21:33:39.803Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/52/505c207f334d51e937cbaa27ff95776e16e2d120e13cbe491cd7b3a70b50/chardet-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25a862cddc6a9ac07023e808aedd297115345fbaabc2690479481ddc0f980e09", size = 870747, upload-time = "2026-04-13T21:32:56.916Z" }, - { url = "https://files.pythonhosted.org/packages/14/4b/d3c79495dee4831b8bebca2790e72cb90f0c5849c940570a7c7e5b70b952/chardet-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7005c88da26fd95d8abb8acbe6281d833e9a9181b03cf49b4546c4555389bd97", size = 853210, upload-time = "2026-04-13T21:32:58.309Z" }, - { url = "https://files.pythonhosted.org/packages/b9/99/f6a822ad1bde25a4c38dc3e770485e78e0893dfd871cd6e18ed3ea3a795e/chardet-7.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc50f28bad067393cce0af9091052c3b8df7a23115afd8ba7b2e0947f0cef1f8", size = 873625, upload-time = "2026-04-13T21:32:59.606Z" }, - { url = "https://files.pythonhosted.org/packages/b1/10/31932775c94a86814f76b41c4a772b52abfb0e6125324f32c6da1196c297/chardet-7.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3da294de1a681097848ab58bd3f2771a674f8039d2d87a5538b28856b815e9", size = 883436, upload-time = "2026-04-13T21:33:01.351Z" }, - { url = "https://files.pythonhosted.org/packages/6c/63/0f43e3acf2c436fdb32a0f904aeb03a2904d2126eed34a042a194d235926/chardet-7.4.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c45e116dd51b66226a53ade3f9f635e870de5399b90e00ce45dcc311093bf4", size = 876589, upload-time = "2026-04-13T21:33:02.636Z" }, - { url = "https://files.pythonhosted.org/packages/5d/a6/e9b8f8a3e99602792b01fa7d0a731737615ab56d8bfd0b52935a0ef88b85/chardet-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:ccc1f83ab4bcfb901cf39e0c4ba6bc6e726fc6264735f10e24ceb5cb47387578", size = 941866, upload-time = "2026-04-13T21:33:04.282Z" }, - { url = "https://files.pythonhosted.org/packages/8c/6c/0a40afdb50a0fe041ab95553b835a8160b6cf0e81edf2ae2fe9f5224cbf9/chardet-7.4.3-py3-none-any.whl", hash = "sha256:1173b74051570cf08099d7429d92e4882d375ad4217f92a6e5240ccfb26f231e", size = 626562, upload-time = "2026-04-13T21:33:38.559Z" }, + { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" }, ] [[package]] name = "charset-normalizer" -version = "3.4.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, - { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, - { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, - { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, - { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, - { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, - { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, - { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, - { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, - { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, - { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, - { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, - { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] [[package]] name = "click" -version = "8.3.3" +version = "8.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, ] [[package]] @@ -472,51 +467,6 @@ version = "1.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c3bcd6c33d2473c1918e0b7f6826a043ca1245dd4e5b/crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e", size = 89670, upload-time = "2010-06-27T14:35:29.538Z" } -[[package]] -name = "cryptography" -version = "47.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/b2/7ffa7fe8207a8c42147ffe70c3e360b228160c1d85dc3faff16aaa3244c0/cryptography-47.0.0.tar.gz", hash = "sha256:9f8e55fe4e63613a5e1cc5819030f27b97742d720203a087802ce4ce9ceb52bb", size = 830863, upload-time = "2026-04-24T19:54:57.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/98/40dfe932134bdcae4f6ab5927c87488754bf9eb79297d7e0070b78dd58e9/cryptography-47.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:160ad728f128972d362e714054f6ba0067cab7fb350c5202a9ae8ae4ce3ef1a0", size = 7912214, upload-time = "2026-04-24T19:53:03.864Z" }, - { url = "https://files.pythonhosted.org/packages/34/c6/2733531243fba725f58611b918056b277692f1033373dcc8bd01af1c05d4/cryptography-47.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b9a8943e359b7615db1a3ba587994618e094ff3d6fa5a390c73d079ce18b3973", size = 4644617, upload-time = "2026-04-24T19:53:06.909Z" }, - { url = "https://files.pythonhosted.org/packages/00/e3/b27be1a670a9b87f855d211cf0e1174a5d721216b7616bd52d8581d912ed/cryptography-47.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5c15764f261394b22aef6b00252f5195f46f2ca300bec57149474e2538b31f8", size = 4668186, upload-time = "2026-04-24T19:53:09.053Z" }, - { url = "https://files.pythonhosted.org/packages/81/b9/8443cfe5d17d482d348cee7048acf502bb89a51b6382f06240fd290d4ca3/cryptography-47.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9c59ab0e0fa3a180a5a9c59f3a5abe3ef90d474bc56d7fadfbe80359491b615b", size = 4651244, upload-time = "2026-04-24T19:53:11.217Z" }, - { url = "https://files.pythonhosted.org/packages/5d/5e/13ed0cdd0eb88ba159d6dd5ebfece8cb901dbcf1ae5ac4072e28b55d3153/cryptography-47.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:34b4358b925a5ea3e14384ca781a2c0ef7ac219b57bb9eacc4457078e2b19f92", size = 5252906, upload-time = "2026-04-24T19:53:13.532Z" }, - { url = "https://files.pythonhosted.org/packages/64/16/ed058e1df0f33d440217cd120d41d5dda9dd215a80b8187f68483185af82/cryptography-47.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0024b87d47ae2399165a6bfb20d24888881eeab83ae2566d62467c5ff0030ce7", size = 4701842, upload-time = "2026-04-24T19:53:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/02/e0/3d30986b30fdbd9e969abbdf8ba00ed0618615144341faeb57f395a084fe/cryptography-47.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:1e47422b5557bb82d3fff997e8d92cff4e28b9789576984f08c248d2b3535d93", size = 4289313, upload-time = "2026-04-24T19:53:17.755Z" }, - { url = "https://files.pythonhosted.org/packages/df/fd/32db38e3ad0cb331f0691cb4c7a8a6f176f679124dee746b3af6633db4d9/cryptography-47.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6f29f36582e6151d9686235e586dd35bb67491f024767d10b842e520dc6a07ac", size = 4650964, upload-time = "2026-04-24T19:53:20.062Z" }, - { url = "https://files.pythonhosted.org/packages/86/53/5395d944dfd48cb1f67917f533c609c34347185ef15eb4308024c876f274/cryptography-47.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a9b761f012a943b7de0e828843c5688d0de94a0578d44d6c85a1bae32f87791f", size = 5207817, upload-time = "2026-04-24T19:53:22.498Z" }, - { url = "https://files.pythonhosted.org/packages/34/4f/e5711b28e1901f7d480a2b1b688b645aa4c77c73f10731ed17e7f7db3f0d/cryptography-47.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4e1de79e047e25d6e9f8cea71c86b4a53aced64134f0f003bbcbf3655fd172c8", size = 4701544, upload-time = "2026-04-24T19:53:24.356Z" }, - { url = "https://files.pythonhosted.org/packages/22/22/c8ddc25de3010fc8da447648f5a092c40e7a8fadf01dd6d255d9c0b9373d/cryptography-47.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef6b3634087f18d2155b1e8ce264e5345a753da2c5fa9815e7d41315c90f8318", size = 4783536, upload-time = "2026-04-24T19:53:26.665Z" }, - { url = "https://files.pythonhosted.org/packages/66/b6/d4a68f4ea999c6d89e8498579cba1c5fcba4276284de7773b17e4fa69293/cryptography-47.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11dbb9f50a0f1bb9757b3d8c27c1101780efb8f0bdecfb12439c22a74d64c001", size = 4926106, upload-time = "2026-04-24T19:53:28.686Z" }, - { url = "https://files.pythonhosted.org/packages/54/ed/5f524db1fade9c013aa618e1c99c6ed05e8ffc9ceee6cda22fed22dda3f4/cryptography-47.0.0-cp311-abi3-win32.whl", hash = "sha256:7fda2f02c9015db3f42bb8a22324a454516ed10a8c29ca6ece6cdbb5efe2a203", size = 3258581, upload-time = "2026-04-24T19:53:31.058Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dc/1b901990b174786569029f67542b3edf72ac068b6c3c8683c17e6a2f5363/cryptography-47.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:f5c3296dab66202f1b18a91fa266be93d6aa0c2806ea3d67762c69f60adc71aa", size = 3775309, upload-time = "2026-04-24T19:53:33.054Z" }, - { url = "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:14432c8a9bcb37009784f9594a62fae211a2ae9543e96c92b2a8e4c3cd5cd0c4", size = 7904072, upload-time = "2026-04-24T19:54:06.411Z" }, - { url = "https://files.pythonhosted.org/packages/01/64/d7b1e54fdb69f22d24a64bb3e88dc718b31c7fb10ef0b9691a3cf7eeea6e/cryptography-47.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:07efe86201817e7d3c18781ca9770bc0db04e1e48c994be384e4602bc38f8f27", size = 4635767, upload-time = "2026-04-24T19:54:08.519Z" }, - { url = "https://files.pythonhosted.org/packages/8b/7b/cca826391fb2a94efdcdfe4631eb69306ee1cff0b22f664a412c90713877/cryptography-47.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b45761c6ec22b7c726d6a829558777e32d0f1c8be7c3f3480f9c912d5ee8a10", size = 4654350, upload-time = "2026-04-24T19:54:10.795Z" }, - { url = "https://files.pythonhosted.org/packages/4c/65/4b57bcc823f42a991627c51c2f68c9fd6eb1393c1756aac876cba2accae2/cryptography-47.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:edd4da498015da5b9f26d38d3bfc2e90257bfa9cbed1f6767c282a0025ae649b", size = 4643394, upload-time = "2026-04-24T19:54:13.275Z" }, - { url = "https://files.pythonhosted.org/packages/f4/c4/2c5fbeea70adbbca2bbae865e1d605d6a4a7f8dbd9d33eaf69645087f06c/cryptography-47.0.0-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9af828c0d5a65c70ec729cd7495a4bf1a67ecb66417b8f02ff125ab8a6326a74", size = 5225777, upload-time = "2026-04-24T19:54:15.18Z" }, - { url = "https://files.pythonhosted.org/packages/7e/b8/ac57107ef32749d2b244e36069bb688792a363aaaa3acc9e3cf84c130315/cryptography-47.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:256d07c78a04d6b276f5df935a9923275f53bd1522f214447fdf365494e2d515", size = 4688771, upload-time = "2026-04-24T19:54:17.835Z" }, - { url = "https://files.pythonhosted.org/packages/56/fc/9f1de22ff8be99d991f240a46863c52d475404c408886c5a38d2b5c3bb26/cryptography-47.0.0-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:5d0e362ff51041b0c0d219cc7d6924d7b8996f57ce5712bdcef71eb3c65a59cc", size = 4270753, upload-time = "2026-04-24T19:54:19.963Z" }, - { url = "https://files.pythonhosted.org/packages/00/68/d70c852797aa68e8e48d12e5a87170c43f67bb4a59403627259dd57d15de/cryptography-47.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1581aef4219f7ca2849d0250edaa3866212fb74bf5667284f46aa92f9e65c1ca", size = 4642911, upload-time = "2026-04-24T19:54:21.818Z" }, - { url = "https://files.pythonhosted.org/packages/a5/51/661cbee74f594c5d97ff82d34f10d5551c085ca4668645f4606ebd22bd5d/cryptography-47.0.0-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:a49a3eb5341b9503fa3000a9a0db033161db90d47285291f53c2a9d2cd1b7f76", size = 5181411, upload-time = "2026-04-24T19:54:24.376Z" }, - { url = "https://files.pythonhosted.org/packages/94/87/f2b6c374a82cf076cfa1416992ac8e8ec94d79facc37aec87c1a5cb72352/cryptography-47.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2207a498b03275d0051589e326b79d4cf59985c99031b05bb292ac52631c37fe", size = 4688262, upload-time = "2026-04-24T19:54:26.946Z" }, - { url = "https://files.pythonhosted.org/packages/14/e2/8b7462f4acf21ec509616f0245018bb197194ab0b65c2ea21a0bdd53c0eb/cryptography-47.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7a02675e2fabd0c0fc04c868b8781863cbf1967691543c22f5470500ff840b31", size = 4775506, upload-time = "2026-04-24T19:54:28.926Z" }, - { url = "https://files.pythonhosted.org/packages/70/75/158e494e4c08dc05e039da5bb48553826bd26c23930cf8d3cd5f21fa8921/cryptography-47.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80887c5cbd1774683cb126f0ab4184567f080071d5acf62205acb354b4b753b7", size = 4912060, upload-time = "2026-04-24T19:54:30.869Z" }, - { url = "https://files.pythonhosted.org/packages/06/bd/0a9d3edbf5eadbac926d7b9b3cd0c4be584eeeae4a003d24d9eda4affbbd/cryptography-47.0.0-cp38-abi3-win32.whl", hash = "sha256:ed67ea4e0cfb5faa5bc7ecb6e2b8838f3807a03758eec239d6c21c8769355310", size = 3248487, upload-time = "2026-04-24T19:54:33.494Z" }, - { url = "https://files.pythonhosted.org/packages/60/80/5681af756d0da3a599b7bdb586fac5a1540f1bcefd2717a20e611ddade45/cryptography-47.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:835d2d7f47cdc53b3224e90810fb1d36ca94ea29cc1801fb4c1bc43876735769", size = 3755737, upload-time = "2026-04-24T19:54:35.408Z" }, - { url = "https://files.pythonhosted.org/packages/1b/a0/928c9ce0d120a40a81aa99e3ba383e87337b9ac9ef9f6db02e4d7822424d/cryptography-47.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f1207974a904e005f762869996cf620e9bf79ecb4622f148550bb48e0eb35a7", size = 3909893, upload-time = "2026-04-24T19:54:38.334Z" }, - { url = "https://files.pythonhosted.org/packages/81/75/d691e284750df5d9569f2b1ce4a00a71e1d79566da83b2b3e5549c84917f/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1a405c08857258c11016777e11c02bacbe7ef596faf259305d282272a3a05cbe", size = 4587867, upload-time = "2026-04-24T19:54:40.619Z" }, - { url = "https://files.pythonhosted.org/packages/07/d6/1b90f1a4e453009730b4545286f0b39bb348d805c11181fc31544e4f9a65/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:20fdbe3e38fb67c385d233c89371fa27f9909f6ebca1cecc20c13518dae65475", size = 4627192, upload-time = "2026-04-24T19:54:42.849Z" }, - { url = "https://files.pythonhosted.org/packages/dc/53/cb358a80e9e359529f496870dd08c102aa8a4b5b9f9064f00f0d6ed5b527/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f7db373287273d8af1414cf95dc4118b13ffdc62be521997b0f2b270771fef50", size = 4587486, upload-time = "2026-04-24T19:54:44.908Z" }, - { url = "https://files.pythonhosted.org/packages/8b/57/aaa3d53876467a226f9a7a82fd14dd48058ad2de1948493442dfa16e2ffd/cryptography-47.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:9fe6b7c64926c765f9dff301f9c1b867febcda5768868ca084e18589113732ab", size = 4626327, upload-time = "2026-04-24T19:54:47.813Z" }, - { url = "https://files.pythonhosted.org/packages/ab/9c/51f28c3550276bcf35660703ba0ab829a90b88be8cd98a71ef23c2413913/cryptography-47.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cffbba3392df0fa8629bb7f43454ee2925059ee158e23c54620b9063912b86c8", size = 3698916, upload-time = "2026-04-24T19:54:49.782Z" }, -] - [[package]] name = "cycler" version = "0.12.1" @@ -528,15 +478,15 @@ wheels = [ [[package]] name = "debugpy" -version = "1.8.20" +version = "1.8.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129, upload-time = "2025-09-17T16:33:20.633Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/56/c3baf5cbe4dd77427fd9aef99fcdade259ad128feeb8a786c246adb838e5/debugpy-1.8.20-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:eada6042ad88fa1571b74bd5402ee8b86eded7a8f7b827849761700aff171f1b", size = 2208318, upload-time = "2026-01-29T23:03:36.481Z" }, - { url = "https://files.pythonhosted.org/packages/9a/7d/4fa79a57a8e69fe0d9763e98d1110320f9ecd7f1f362572e3aafd7417c9d/debugpy-1.8.20-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:7de0b7dfeedc504421032afba845ae2a7bcc32ddfb07dae2c3ca5442f821c344", size = 3171493, upload-time = "2026-01-29T23:03:37.775Z" }, - { url = "https://files.pythonhosted.org/packages/7d/f2/1e8f8affe51e12a26f3a8a8a4277d6e60aa89d0a66512f63b1e799d424a4/debugpy-1.8.20-cp311-cp311-win32.whl", hash = "sha256:773e839380cf459caf73cc533ea45ec2737a5cc184cf1b3b796cd4fd98504fec", size = 5209240, upload-time = "2026-01-29T23:03:39.109Z" }, - { url = "https://files.pythonhosted.org/packages/d5/92/1cb532e88560cbee973396254b21bece8c5d7c2ece958a67afa08c9f10dc/debugpy-1.8.20-cp311-cp311-win_amd64.whl", hash = "sha256:1f7650546e0eded1902d0f6af28f787fa1f1dbdbc97ddabaf1cd963a405930cb", size = 5233481, upload-time = "2026-01-29T23:03:40.659Z" }, - { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, + { url = "https://files.pythonhosted.org/packages/d8/53/3af72b5c159278c4a0cf4cffa518675a0e73bdb7d1cac0239b815502d2ce/debugpy-1.8.17-cp311-cp311-macosx_15_0_universal2.whl", hash = "sha256:d3fce3f0e3de262a3b67e69916d001f3e767661c6e1ee42553009d445d1cd840", size = 2207154, upload-time = "2025-09-17T16:33:29.457Z" }, + { url = "https://files.pythonhosted.org/packages/8f/6d/204f407df45600e2245b4a39860ed4ba32552330a0b3f5f160ae4cc30072/debugpy-1.8.17-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:c6bdf134457ae0cac6fb68205776be635d31174eeac9541e1d0c062165c6461f", size = 3170322, upload-time = "2025-09-17T16:33:30.837Z" }, + { url = "https://files.pythonhosted.org/packages/f2/13/1b8f87d39cf83c6b713de2620c31205299e6065622e7dd37aff4808dd410/debugpy-1.8.17-cp311-cp311-win32.whl", hash = "sha256:e79a195f9e059edfe5d8bf6f3749b2599452d3e9380484cd261f6b7cd2c7c4da", size = 5155078, upload-time = "2025-09-17T16:33:33.331Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c5/c012c60a2922cc91caa9675d0ddfbb14ba59e1e36228355f41cab6483469/debugpy-1.8.17-cp311-cp311-win_amd64.whl", hash = "sha256:b532282ad4eca958b1b2d7dbcb2b7218e02cb934165859b918e3b6ba7772d3f4", size = 5179011, upload-time = "2025-09-17T16:33:35.711Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210, upload-time = "2025-09-17T16:34:25.835Z" }, ] [[package]] @@ -572,15 +522,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] -[[package]] -name = "distro" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, -] - [[package]] name = "dnspython" version = "2.8.0" @@ -598,11 +539,11 @@ sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf57 [[package]] name = "docstring-parser" -version = "0.18.0" +version = "0.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/4d/f332313098c1de1b2d2ff91cf2674415cc7cddab2ca1b01ae29774bd5fdf/docstring_parser-0.18.0.tar.gz", hash = "sha256:292510982205c12b1248696f44959db3cdd1740237a968ea1e2e7a900eeb2015", size = 29341, upload-time = "2026-04-14T04:09:19.867Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl", hash = "sha256:b3fcbed555c47d8479be0796ef7e19c2670d428d72e96da63f3a40122860374b", size = 22484, upload-time = "2026-04-14T04:09:18.638Z" }, + { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, ] [[package]] @@ -625,17 +566,16 @@ wheels = [ [[package]] name = "fastavro" -version = "1.12.2" +version = "1.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6e/5b/ccb338db71f347e3bc031d268bf6dc41e5ead63b6997b8e72af92f05e18e/fastavro-1.12.2.tar.gz", hash = "sha256:3c79502d56cf6b76210032e1c53494ddfbc73c140bccf2ef4092b3f0825323ab", size = 1030127, upload-time = "2026-04-24T14:36:01.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz", hash = "sha256:2f285be49e45bc047ab2f6bed040bb349da85db3f3c87880e4b92595ea093b2b", size = 1025661, upload-time = "2025-10-10T15:40:55.41Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/77/058f3c93348624cb695399b27f3f0c1c3d1190586065797e4a48f75d4147/fastavro-1.12.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d48cd7094598a7e9d4297e8bf4bbe0dc9dc2ba4367d83dbb603e3b3c6aa35566", size = 974559, upload-time = "2026-04-24T14:36:17.172Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ef/08bbfa643addd2b98a9ce536613e2098928aa5e3ca098fd5b74f3c03b96a/fastavro-1.12.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:070c6134604bd7b6fd44409406ac50445339682b2e872885db2e859f92d22e93", size = 3352777, upload-time = "2026-04-24T14:36:19.679Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ec/55c11108529bdb59e635899f737651f729485ea5af36e128fb6560969c3d/fastavro-1.12.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b73d50978d5e57416fa68461f9f3c8f39ea39e761cb1e12f919745adefe26a7", size = 3387036, upload-time = "2026-04-24T14:36:21.794Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b3/4459f7c61804e9b42b49f02fba8fbbb041af76c7cab43cee4018532ecd00/fastavro-1.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c57a9920400166398695d92580eca21fd7a79f3c67d691ac7e20a7d1b5300735", size = 3284780, upload-time = "2026-04-24T14:36:24.193Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e3/d7f510b9b8c7b73409a6232a9a8d282faa8560f85d024d7212e4c5dff3df/fastavro-1.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:81f6108f3ac292fb6cd05758c9e531389d8fc5e94e8c949b9298f4fb0a239662", size = 3368557, upload-time = "2026-04-24T14:36:26.667Z" }, - { url = "https://files.pythonhosted.org/packages/cb/10/14fa0abf8e7da07258393ae2b783dd4bb60d1fb93ad790296d27561f33ce/fastavro-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:eec44256856fd59d29d1f1d0950ace18a58e4228e7d49de5d5e1b1875b227dde", size = 446499, upload-time = "2026-04-24T14:36:28.547Z" }, - { url = "https://files.pythonhosted.org/packages/86/d2/c36f646296794c05d29a07bec84a6c56bfd285203e389a8954987ec1c515/fastavro-1.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:ecd1b23ea7f9af09c865ac8503d07afd7e6bf782d76bb83cbbdba15b7a0db807", size = 388198, upload-time = "2026-04-24T14:36:29.791Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e9/31c64b47cefc0951099e7c0c8c8ea1c931edd1350f34d55c27cbfbb08df1/fastavro-1.12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b632b713bc5d03928a87d811fa4a11d5f25cd43e79c161e291c7d3f7aa740fd", size = 1016585, upload-time = "2025-10-10T15:41:13.717Z" }, + { url = "https://files.pythonhosted.org/packages/10/76/111560775b548f5d8d828c1b5285ff90e2d2745643fb80ecbf115344eea4/fastavro-1.12.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa7ab3769beadcebb60f0539054c7755f63bd9cf7666e2c15e615ab605f89a8", size = 3404629, upload-time = "2025-10-10T15:41:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/b0/07/6bb93cb963932146c2b6c5c765903a0a547ad9f0f8b769a4a9aad8c06369/fastavro-1.12.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123fb221df3164abd93f2d042c82f538a1d5a43ce41375f12c91ce1355a9141e", size = 3428594, upload-time = "2025-10-10T15:41:17.779Z" }, + { url = "https://files.pythonhosted.org/packages/d1/67/8115ec36b584197ea737ec79e3499e1f1b640b288d6c6ee295edd13b80f6/fastavro-1.12.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:632a4e3ff223f834ddb746baae0cc7cee1068eb12c32e4d982c2fee8a5b483d0", size = 3344145, upload-time = "2025-10-10T15:41:19.89Z" }, + { url = "https://files.pythonhosted.org/packages/9e/9e/a7cebb3af967e62539539897c10138fa0821668ec92525d1be88a9cd3ee6/fastavro-1.12.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:83e6caf4e7a8717d932a3b1ff31595ad169289bbe1128a216be070d3a8391671", size = 3431942, upload-time = "2025-10-10T15:41:22.076Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d1/7774ddfb8781c5224294c01a593ebce2ad3289b948061c9701bd1903264d/fastavro-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:b91a0fe5a173679a6c02d53ca22dcaad0a2c726b74507e0c1c2e71a7c3f79ef9", size = 450542, upload-time = "2025-10-10T15:41:23.333Z" }, ] [[package]] @@ -664,7 +604,7 @@ resolution-markers = [ "sys_platform != 'darwin'", ] dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform != 'darwin'" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/fbgemm_gpu-1.3.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4154e803ba762906a604a72aa41685fdd49459fce55cea79d42ac7c45c8770ca", upload-time = "2025-08-22T18:49:45Z" }, @@ -684,36 +624,37 @@ wheels = [ [[package]] name = "filelock" -version = "3.29.0" +version = "3.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, + { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, ] [[package]] name = "flatbuffers" -version = "25.12.19" +version = "25.9.23" source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/1f/3ee70b0a55137442038f2a33469cc5fddd7e0ad2abf83d7497c18a2b6923/flatbuffers-25.9.23.tar.gz", hash = "sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12", size = 22067, upload-time = "2025-09-24T05:25:30.106Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" }, + { url = "https://files.pythonhosted.org/packages/ee/1b/00a78aa2e8fbd63f9af08c9c19e6deb3d5d66b4dda677a0f61654680ee89/flatbuffers-25.9.23-py2.py3-none-any.whl", hash = "sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2", size = 30869, upload-time = "2025-09-24T05:25:28.912Z" }, ] [[package]] name = "fonttools" -version = "4.62.1" +version = "4.60.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823, upload-time = "2025-09-29T21:13:27.129Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/23ff32561ec8d45a4d48578b4d241369d9270dc50926c017570e60893701/fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40975849bac44fb0b9253d77420c6d8b523ac4dcdcefeff6e4d706838a5b80f7", size = 2871039, upload-time = "2026-03-13T13:52:33.127Z" }, - { url = "https://files.pythonhosted.org/packages/24/7f/66d3f8a9338a9b67fe6e1739f47e1cd5cee78bd3bc1206ef9b0b982289a5/fonttools-4.62.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9dde91633f77fa576879a0c76b1d89de373cae751a98ddf0109d54e173b40f14", size = 2416346, upload-time = "2026-03-13T13:52:35.676Z" }, - { url = "https://files.pythonhosted.org/packages/aa/53/5276ceba7bff95da7793a07c5284e1da901cf00341ce5e2f3273056c0cca/fonttools-4.62.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6acb4109f8bee00fec985c8c7afb02299e35e9c94b57287f3ea542f28bd0b0a7", size = 5100897, upload-time = "2026-03-13T13:52:38.102Z" }, - { url = "https://files.pythonhosted.org/packages/cc/a1/40a5c4d8e28b0851d53a8eeeb46fbd73c325a2a9a165f290a5ed90e6c597/fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1c5c25671ce8805e0d080e2ffdeca7f1e86778c5cbfbeae86d7f866d8830517b", size = 5071078, upload-time = "2026-03-13T13:52:41.305Z" }, - { url = "https://files.pythonhosted.org/packages/e3/be/d378fca4c65ea1956fee6d90ace6e861776809cbbc5af22388a090c3c092/fonttools-4.62.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a5d8825e1140f04e6c99bb7d37a9e31c172f3bc208afbe02175339e699c710e1", size = 5076908, upload-time = "2026-03-13T13:52:44.122Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d9/ae6a1d0693a4185a84605679c8a1f719a55df87b9c6e8e817bfdd9ef5936/fonttools-4.62.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:268abb1cb221e66c014acc234e872b7870d8b5d4657a83a8f4205094c32d2416", size = 5202275, upload-time = "2026-03-13T13:52:46.591Z" }, - { url = "https://files.pythonhosted.org/packages/54/6c/af95d9c4efb15cabff22642b608342f2bd67137eea6107202d91b5b03184/fonttools-4.62.1-cp311-cp311-win32.whl", hash = "sha256:942b03094d7edbb99bdf1ae7e9090898cad7bf9030b3d21f33d7072dbcb51a53", size = 2293075, upload-time = "2026-03-13T13:52:48.711Z" }, - { url = "https://files.pythonhosted.org/packages/d3/97/bf54c5b3f2be34e1f143e6db838dfdc54f2ffa3e68c738934c82f3b2a08d/fonttools-4.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:e8514f4924375f77084e81467e63238b095abda5107620f49421c368a6017ed2", size = 2344593, upload-time = "2026-03-13T13:52:50.725Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, + { url = "https://files.pythonhosted.org/packages/ea/85/639aa9bface1537e0fb0f643690672dde0695a5bbbc90736bc571b0b1941/fonttools-4.60.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f", size = 2831872, upload-time = "2025-09-29T21:11:20.329Z" }, + { url = "https://files.pythonhosted.org/packages/6b/47/3c63158459c95093be9618794acb1067b3f4d30dcc5c3e8114b70e67a092/fonttools-4.60.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2", size = 2356990, upload-time = "2025-09-29T21:11:22.754Z" }, + { url = "https://files.pythonhosted.org/packages/94/dd/1934b537c86fcf99f9761823f1fc37a98fbd54568e8e613f29a90fed95a9/fonttools-4.60.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914", size = 5042189, upload-time = "2025-09-29T21:11:25.061Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d2/9f4e4c4374dd1daa8367784e1bd910f18ba886db1d6b825b12edf6db3edc/fonttools-4.60.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1", size = 4978683, upload-time = "2025-09-29T21:11:27.693Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c4/0fb2dfd1ecbe9a07954cc13414713ed1eab17b1c0214ef07fc93df234a47/fonttools-4.60.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d", size = 5021372, upload-time = "2025-09-29T21:11:30.257Z" }, + { url = "https://files.pythonhosted.org/packages/0c/d5/495fc7ae2fab20223cc87179a8f50f40f9a6f821f271ba8301ae12bb580f/fonttools-4.60.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa", size = 5132562, upload-time = "2025-09-29T21:11:32.737Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fa/021dab618526323c744e0206b3f5c8596a2e7ae9aa38db5948a131123e83/fonttools-4.60.1-cp311-cp311-win32.whl", hash = "sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258", size = 2230288, upload-time = "2025-09-29T21:11:35.015Z" }, + { url = "https://files.pythonhosted.org/packages/bb/78/0e1a6d22b427579ea5c8273e1c07def2f325b977faaf60bb7ddc01456cb1/fonttools-4.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf", size = 2278184, upload-time = "2025-09-29T21:11:37.434Z" }, + { url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175, upload-time = "2025-09-29T21:13:24.134Z" }, ] [[package]] @@ -743,20 +684,20 @@ wheels = [ [[package]] name = "fsspec" -version = "2026.3.0" +version = "2025.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/cf/b50ddf667c15276a9ab15a70ef5f257564de271957933ffea49d2cdbcdfb/fsspec-2026.3.0.tar.gz", hash = "sha256:1ee6a0e28677557f8c2f994e3eea77db6392b4de9cd1f5d7a9e87a0ae9d01b41", size = 313547, upload-time = "2026-03-27T19:11:14.892Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/1f/5f4a3cd9e4440e9d9bc78ad0a91a1c8d46b4d429d5239ebe6793c9fe5c41/fsspec-2026.3.0-py3-none-any.whl", hash = "sha256:d2ceafaad1b3457968ed14efa28798162f1638dbb5d2a6868a2db002a5ee39a4", size = 202595, upload-time = "2026-03-27T19:11:13.595Z" }, + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, ] [[package]] name = "gast" -version = "0.7.0" +version = "0.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/f6/e73969782a2ecec280f8a176f2476149dd9dba69d5f8779ec6108a7721e6/gast-0.7.0.tar.gz", hash = "sha256:0bb14cd1b806722e91ddbab6fb86bba148c22b40e7ff11e248974e04c8adfdae", size = 33630, upload-time = "2025-11-29T15:30:05.266Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3c/14/c566f5ca00c115db7725263408ff952b8ae6d6a4e792ef9c84e77d9af7a1/gast-0.6.0.tar.gz", hash = "sha256:88fc5300d32c7ac6ca7b515310862f71e6fdf2c029bbec7c66c0f5dd47b6b1fb", size = 27708, upload-time = "2024-06-27T20:31:49.527Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/33/f1c6a276de27b7d7339a34749cc33fa87f077f921969c47185d34a887ae2/gast-0.7.0-py3-none-any.whl", hash = "sha256:99cbf1365633a74099f69c59bd650476b96baa5ef196fec88032b00b31ba36f7", size = 22966, upload-time = "2025-11-29T15:30:03.983Z" }, + { url = "https://files.pythonhosted.org/packages/a3/61/8001b38461d751cd1a0c3a6ae84346796a5758123f3ed97a1b121dfbf4f3/gast-0.6.0-py3-none-any.whl", hash = "sha256:52b182313f7330389f72b069ba00f174cfe2a06411099547288839c6cbafbd54", size = 21173, upload-time = "2024-07-09T13:15:15.615Z" }, ] [[package]] @@ -797,30 +738,26 @@ experimental = [ ] pyg27-torch28-cpu = [ { name = "fbgemm-gpu", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, - { name = "pyg-lib", version = "0.6.0+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, + { name = "pyg-lib", version = "0.5.0+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, { name = "torch", version = "2.8.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch-cluster", version = "1.6.3", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "torch-cluster", version = "1.6.3+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch-cluster", version = "1.6.3+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, { name = "torch-geometric" }, - { name = "torch-scatter", version = "2.1.2", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "torch-scatter", version = "2.1.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch-sparse", version = "0.6.18", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "torch-sparse", version = "0.6.18+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch-spline-conv", version = "1.2.2", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, - { name = "torch-spline-conv", version = "1.2.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torchrec", version = "1.5.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, + { name = "torch-scatter", version = "2.1.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torch-sparse", version = "0.6.18+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torch-spline-conv", version = "1.2.2+pt28cpu", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" }, marker = "sys_platform != 'darwin'" }, + { name = "torchrec", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, ] pyg27-torch28-cu128 = [ { name = "fbgemm-gpu", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, - { name = "pyg-lib", version = "0.6.0+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, + { name = "pyg-lib", version = "0.5.0+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, { name = "torch-cluster", version = "1.6.3+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, { name = "torch-geometric", marker = "sys_platform != 'darwin'" }, { name = "torch-scatter", version = "2.1.2+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, { name = "torch-sparse", version = "0.6.18+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, { name = "torch-spline-conv", version = "1.2.2+pt28cu128", source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" }, marker = "sys_platform != 'darwin'" }, - { name = "torchrec", version = "1.5.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, + { name = "torchrec", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform != 'darwin'" }, ] transform = [ { name = "apache-beam", extra = ["gcp"] }, @@ -1037,7 +974,7 @@ source = { directory = "gigl-core" } [[package]] name = "google-api-core" -version = "2.30.3" +version = "2.28.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-auth" }, @@ -1046,9 +983,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/16/ce/502a57fb0ec752026d24df1280b162294b22a0afb98a326084f9a979138b/google_api_core-2.30.3.tar.gz", hash = "sha256:e601a37f148585319b26db36e219df68c5d07b6382cff2d580e83404e44d641b", size = 177001, upload-time = "2026-04-10T00:41:28.035Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759, upload-time = "2025-10-28T21:34:51.529Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/15/e56f351cf6ef1cfea58e6ac226a7318ed1deb2218c4b3cc9bd9e4b786c5a/google_api_core-2.30.3-py3-none-any.whl", hash = "sha256:a85761ba72c444dad5d611c2220633480b2b6be2521eca69cca2dbb3ffd6bfe8", size = 173274, upload-time = "2026-04-09T22:57:16.198Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706, upload-time = "2025-10-28T21:34:50.151Z" }, ] [package.optional-dependencies] @@ -1062,12 +999,12 @@ name = "google-api-python-client" version = "1.12.11" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, - { name = "google-auth-httplib2" }, - { name = "httplib2" }, - { name = "six" }, - { name = "uritemplate" }, + { name = "google-api-core", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "google-auth", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "google-auth-httplib2", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "httplib2", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "six", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "uritemplate", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dd/12/07e966db6bfa4bd440af2f83ca6cc7bd61c2f4859992b7103437e8a98ce1/google-api-python-client-1.12.11.tar.gz", hash = "sha256:1b4bd42a46321e13c0542a9e4d96fa05d73626f07b39f83a73a947d70ca706a9", size = 146876, upload-time = "2022-03-15T13:49:56.711Z" } wheels = [ @@ -1088,20 +1025,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/19/da/aefc4cf4c168b5d87 [[package]] name = "google-auth" -version = "2.49.2" +version = "2.42.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography" }, + { name = "cachetools" }, { name = "pyasn1-modules" }, + { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", size = 333958, upload-time = "2026-04-10T00:41:21.888Z" } +sdist = { url = "https://files.pythonhosted.org/packages/25/6b/22a77135757c3a7854c9f008ffed6bf4e8851616d77faf13147e9ab5aae6/google_auth-2.42.1.tar.gz", hash = "sha256:30178b7a21aa50bffbdc1ffcb34ff770a2f65c712170ecd5446c4bef4dc2b94e", size = 295541, upload-time = "2025-10-30T16:42:19.381Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", size = 240638, upload-time = "2026-04-10T00:41:14.501Z" }, -] - -[package.optional-dependencies] -requests = [ - { name = "requests" }, + { url = "https://files.pythonhosted.org/packages/92/05/adeb6c495aec4f9d93f9e2fc29eeef6e14d452bba11d15bdb874ce1d5b10/google_auth-2.42.1-py2.py3-none-any.whl", hash = "sha256:eb73d71c91fc95dbd221a2eb87477c278a355e7367a35c0d84e6b0e5f9b4ad11", size = 222550, upload-time = "2025-10-30T16:42:17.878Z" }, ] [[package]] @@ -1119,7 +1052,7 @@ wheels = [ [[package]] name = "google-cloud-aiplatform" -version = "1.148.1" +version = "1.124.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docstring-parser" }, @@ -1133,16 +1066,17 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, { name = "pydantic" }, + { name = "shapely" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/f3/b2a9417014c93858a2e3266134f931eefd972c2d410b25d7b8782fc6f143/google_cloud_aiplatform-1.148.1.tar.gz", hash = "sha256:75d605fba34e68714bd08e1e482755d0a6e3ae972805f809d088e686c30879e7", size = 10278758, upload-time = "2026-04-17T23:45:26.738Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ad/a3da0cbb78a933544ef2ca3db3da242a2217a52d823beb3ea129995c00df/google_cloud_aiplatform-1.124.0.tar.gz", hash = "sha256:cf565f2ce3dac19c6502a65d89c89760000fde1d531be54949c6232ba2a168fd", size = 9755170, upload-time = "2025-10-30T19:59:22.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/5b/e3515d7bbba602c2b0f6a0da5431785e897252443682e4735d0e6873dc8f/google_cloud_aiplatform-1.148.1-py2.py3-none-any.whl", hash = "sha256:035101e2d8e65c6a706cc3930b2452de7ddcbde50dd130320fcea0d8b03b0c5a", size = 8434481, upload-time = "2026-04-17T23:45:22.919Z" }, + { url = "https://files.pythonhosted.org/packages/c5/46/c20db72a9389c5b6595c2c3fed9abe2b05d3658fe2c07657f7324623cb63/google_cloud_aiplatform-1.124.0-py2.py3-none-any.whl", hash = "sha256:047685f0ee0ab7346ba7d437904357077e3362b32a951c5038a9ac789c5f9148", size = 8112493, upload-time = "2025-10-30T19:59:19.42Z" }, ] [[package]] name = "google-cloud-appengine-logging" -version = "1.9.0" +version = "1.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1151,27 +1085,27 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bc/02/800897064ca6f1a26835cdf23939c4b93e38a30f3fb5c7cec7c01ae2edc2/google_cloud_appengine_logging-1.9.0.tar.gz", hash = "sha256:ff397f0bbc1485f979ab45767c38e0f676c9598c97c384f7412216e6ea22f805", size = 17963, upload-time = "2026-03-30T22:51:33.556Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/260266e5fa7283b721bbef012f3223d514e2569446f56786fe0c80aa0fd4/google_cloud_appengine_logging-1.7.0.tar.gz", hash = "sha256:ea9ce73430cfc99f8957fd7df97733f9a759d4caab65e19d63a7474f012ffd94", size = 16729, upload-time = "2025-10-17T02:33:40.842Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/4a/304d42664ab2afbe7be39559c9eb3f81dd06e7ac9284f9f36f726f15939d/google_cloud_appengine_logging-1.9.0-py3-none-any.whl", hash = "sha256:bbf3a7e4dc171678f7f481259d1f68c3ae7d337530f1f2361f8a0b214dbcfe36", size = 18333, upload-time = "2026-03-30T22:49:39.045Z" }, + { url = "https://files.pythonhosted.org/packages/24/45/99bb629a23639d868c693748598796d7f8e60f62289795b6f310d3328b19/google_cloud_appengine_logging-1.7.0-py3-none-any.whl", hash = "sha256:cfd28bc61a030008381a646d112ebe2734bf72abc8c12afc47d035a2c9b041fe", size = 16924, upload-time = "2025-10-17T02:30:48.802Z" }, ] [[package]] name = "google-cloud-audit-log" -version = "0.5.0" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/9f/3aedb3ce1d58c58ec7dd06b3964836eabfd17a16a95b60c8f609c0afff7f/google_cloud_audit_log-0.5.0.tar.gz", hash = "sha256:3b32d5e77db634c46fbd6c5e01f5bda836f420dfbb21d730501c75e9fab4e4a4", size = 44670, upload-time = "2026-03-30T22:50:42.295Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/d2/ad96950410f8a05e921a6da2e1a6ba4aeca674bbb5dda8200c3c7296d7ad/google_cloud_audit_log-0.4.0.tar.gz", hash = "sha256:8467d4dcca9f3e6160520c24d71592e49e874838f174762272ec10e7950b6feb", size = 44682, upload-time = "2025-10-17T02:33:44.641Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/40/79fa535b6e3321d5e07b2a9ab4bb63860d3fea12230c765837881348003c/google_cloud_audit_log-0.5.0-py3-none-any.whl", hash = "sha256:3f4632f25bf67446fa9085c52868f3cb42fb1afbab9489ba8978e30991afc79f", size = 44862, upload-time = "2026-03-30T22:47:57.533Z" }, + { url = "https://files.pythonhosted.org/packages/9b/25/532886995f11102ad6de290496de5db227bd3a73827702445928ad32edcb/google_cloud_audit_log-0.4.0-py3-none-any.whl", hash = "sha256:6b88e2349df45f8f4cc0993b687109b1388da1571c502dc1417efa4b66ec55e0", size = 44890, upload-time = "2025-10-17T02:30:55.11Z" }, ] [[package]] name = "google-cloud-bigquery" -version = "3.41.0" +version = "3.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1182,14 +1116,14 @@ dependencies = [ { name = "python-dateutil" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ce/13/6515c7aab55a4a0cf708ffd309fb9af5bab54c13e32dc22c5acd6497193c/google_cloud_bigquery-3.41.0.tar.gz", hash = "sha256:2217e488b47ed576360c9b2cc07d59d883a54b83167c0ef37f915c26b01a06fe", size = 513434, upload-time = "2026-03-30T22:50:55.347Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/b2/a17e40afcf9487e3d17db5e36728ffe75c8d5671c46f419d7b6528a5728a/google_cloud_bigquery-3.38.0.tar.gz", hash = "sha256:8afcb7116f5eac849097a344eb8bfda78b7cfaae128e60e019193dd483873520", size = 503666, upload-time = "2025-09-17T20:33:33.47Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/33/1d3902efadef9194566d499d61507e1f038454e0b55499d2d7f8ab2a4fee/google_cloud_bigquery-3.41.0-py3-none-any.whl", hash = "sha256:2a5b5a737b401cbd824a6e5eac7554100b878668d908e6548836b5d8aaa4dcaa", size = 262343, upload-time = "2026-03-30T22:48:45.444Z" }, + { url = "https://files.pythonhosted.org/packages/39/3c/c8cada9ec282b29232ed9aed5a0b5cca6cf5367cb2ffa8ad0d2583d743f1/google_cloud_bigquery-3.38.0-py3-none-any.whl", hash = "sha256:e06e93ff7b245b239945ef59cb59616057598d369edac457ebf292bd61984da6", size = 259257, upload-time = "2025-09-17T20:33:31.404Z" }, ] [[package]] name = "google-cloud-bigquery-storage" -version = "2.37.0" +version = "2.34.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1198,14 +1132,14 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/13/31/5c6fa9e7b8e266a765ec80d13a2b2852cb0a6d3733572e7dbdc0cb39003c/google_cloud_bigquery_storage-2.37.0.tar.gz", hash = "sha256:f88ee7f1e49db1e639da3d9a8b79835ca4bc47afbb514fb2adfc0ccb41a7fd97", size = 310578, upload-time = "2026-03-30T22:51:13.418Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/d2/42787f7843c1ebb386f1c54dd8d7cc16dc85d661dca74041626cd5d459e0/google_cloud_bigquery_storage-2.34.0.tar.gz", hash = "sha256:221740a991b3173027ebb0f3aa5f06c65bdf90fc4eb1b71da798093b6bf6d22d", size = 293674, upload-time = "2025-10-28T17:26:30.976Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/0e/2950d4d0160300f51c7397a080b1685d3e25b40badb2c96f03d58d0ee868/google_cloud_bigquery_storage-2.37.0-py3-none-any.whl", hash = "sha256:1e319c27ef60fc31030f6e0b52e5e891e1cdd50551effe8c6f673a4c3c56fcb6", size = 306678, upload-time = "2026-03-30T22:47:42.333Z" }, + { url = "https://files.pythonhosted.org/packages/46/7d/b347996d12a9da424eaccbbdcf831be39dfd2f81400fa912804379a5a237/google_cloud_bigquery_storage-2.34.0-py3-none-any.whl", hash = "sha256:5c1b55f2a33bfb0730cf5a2f7e4f0cc6a7166d9026142ab78c2ffd5130884c46", size = 295668, upload-time = "2025-10-28T17:26:19.792Z" }, ] [[package]] name = "google-cloud-bigtable" -version = "2.36.0" +version = "2.34.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1216,27 +1150,27 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/f5/ad2a48306a7e8d5e47b5203703ce9c343389e60f025b5ea3f0c62ba92129/google_cloud_bigtable-2.36.0.tar.gz", hash = "sha256:d5987733c2f60c739f93f259d2037858411cc994ac37cdfbccb6bb159f3ca43e", size = 796035, upload-time = "2026-04-02T21:23:33.248Z" } +sdist = { url = "https://files.pythonhosted.org/packages/29/20/8a29e1d5858ba76f443dc527a223e769347b915cb060a9f19250241aa38a/google_cloud_bigtable-2.34.0.tar.gz", hash = "sha256:773258b00cd3f9a3a35639cc38bd711f4f1418aaa0c8d70cb028978ed98dc2c2", size = 766606, upload-time = "2025-10-22T19:04:53.645Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/19/1cc695fa8489ef446a70ee9e983c12f4b47e0649005758035530eaec4b1c/google_cloud_bigtable-2.36.0-py3-none-any.whl", hash = "sha256:21b2f41231b7368a550b44d5b493b811b3507fcb23eb26d00005cd3f205f2207", size = 552799, upload-time = "2026-04-02T21:23:20.475Z" }, + { url = "https://files.pythonhosted.org/packages/55/6d/aa44110504b4b9d125f1cc9715b72a178ebbe5cb79698e7a95893c391e56/google_cloud_bigtable-2.34.0-py3-none-any.whl", hash = "sha256:a4a8db4903840cd3f89fb19c060eea2e7c09c1265cb0538cfc11288dbc6000e4", size = 537041, upload-time = "2025-10-22T19:04:52.014Z" }, ] [[package]] name = "google-cloud-core" -version = "2.5.1" +version = "2.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core" }, { name = "google-auth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/24/6ca08b0a03c7b0c620427503ab00353a4ae806b848b93bcea18b6b76fde6/google_cloud_core-2.5.1.tar.gz", hash = "sha256:3dc94bdec9d05a31d9f355045ed0f369fbc0d8c665076c734f065d729800f811", size = 36078, upload-time = "2026-03-30T22:50:08.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/d9/5bb050cb32826466aa9b25f79e2ca2879fe66cb76782d4ed798dd7506151/google_cloud_core-2.5.1-py3-none-any.whl", hash = "sha256:ea62cdf502c20e3e14be8a32c05ed02113d7bef454e40ff3fab6fe1ec9f1f4e7", size = 29452, upload-time = "2026-03-30T22:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, ] [[package]] name = "google-cloud-dataproc" -version = "5.27.0" +version = "5.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1246,31 +1180,30 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/93/fd399cba4c7cc9b2b56f0f686b8bf810fe374e2b6fa4682a59b9661885d1/google_cloud_dataproc-5.27.0.tar.gz", hash = "sha256:4ed0b248f0f825ce8ed3d29ddd50fa4962321b70cb045416962c1ba7b74b46ec", size = 589166, upload-time = "2026-04-13T22:27:17.991Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/45/9010c4c1176d745aad3e8832caa752a2b05bd9a8e216ea86f1aae5f72924/google_cloud_dataproc-5.23.0.tar.gz", hash = "sha256:94b385bdbf67b7e2b6f53ca0953ac2df2195e13e131bad132efc866459f606a3", size = 569152, upload-time = "2025-10-17T02:34:30.034Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/da/f4b6723f048c2b89466e7a978338954fc4ed4f501c94bd6c97ec49fd8526/google_cloud_dataproc-5.27.0-py3-none-any.whl", hash = "sha256:7eec2ee649ab28747d304a3acf26a78f0703d73ea8f93a4cb85039fee4f4864f", size = 494239, upload-time = "2026-04-13T22:27:15.981Z" }, + { url = "https://files.pythonhosted.org/packages/fb/fa/7e5ebe496c73dbc6291c94b40e1e3062d7ffeb52d8ffd4b13cbcedfd8500/google_cloud_dataproc-5.23.0-py3-none-any.whl", hash = "sha256:2b949b4d4355f25d09707e15cdb065eee93c2ddc21f2dd5c042eafa0dc9f8e0a", size = 484197, upload-time = "2025-10-17T02:32:33.404Z" }, ] [[package]] name = "google-cloud-datastore" -version = "2.24.0" +version = "2.21.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, { name = "google-auth" }, { name = "google-cloud-core" }, - { name = "grpcio" }, { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8f/69/1389655f6949d0da0c1c5a359e64aece0a199ba177b33b7a070aa86bf672/google_cloud_datastore-2.24.0.tar.gz", hash = "sha256:f087c02a6aa4ac68bbf17f0c048ae3ee355856bf09c51439bfba193741387792", size = 266157, upload-time = "2026-03-30T22:49:52.688Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/e1/82174567df885c78d10af94755443e0d1a69d02309aed55fa3b412297c53/google_cloud_datastore-2.21.0.tar.gz", hash = "sha256:eee454dd4a55f5b327f9f344928ff1a09a6f77c23d5e3d908ad31a13cc2f4073", size = 261373, upload-time = "2025-04-15T01:05:21.033Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/88/357efc6b331fd29155dcb92a5dfb0030a8a6feddb7bbf8a6215defbed6c7/google_cloud_datastore-2.24.0-py3-none-any.whl", hash = "sha256:81f1d1c12c2906f59507f72742545ab04c38f62ed70b0542057e3cf04a53aa65", size = 207690, upload-time = "2026-03-30T22:47:49.48Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a7/6ecb2f147cb9da8feb5bdbf959d481ca62f2e27106f3446b67dc8a892659/google_cloud_datastore-2.21.0-py2.py3-none-any.whl", hash = "sha256:f303f27cd1983383f20bd227019cd8a7897419e0ec6b878367c58c66245f9d9b", size = 208009, upload-time = "2025-04-15T01:05:19.088Z" }, ] [[package]] name = "google-cloud-dlp" -version = "3.36.0" +version = "3.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1279,14 +1212,14 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/fd/7cc493dedfcf2816a51034349d1961dcc0d62e5a6ad6152a62456fdf9631/google_cloud_dlp-3.36.0.tar.gz", hash = "sha256:a239a214303ca08ccdcdd7b6ee270d2ce4e4e81955a05648ffdb383204bf5ca6", size = 280086, upload-time = "2026-04-10T00:41:23.883Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/71/8c7f32b222a01ed7ab616e4447ed3eaeec9543ef4afd0e4ea3ca37c4ad96/google_cloud_dlp-3.33.0.tar.gz", hash = "sha256:a910be118ec3c8898c38521610d62f4a16f333a4deb2abeb773e720f6e5f67e3", size = 273468, upload-time = "2025-10-17T02:34:39.622Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/b1/f3c8a58d6c267308c26ba951003adb6b63f53516eb1e9c91981ad762a5fe/google_cloud_dlp-3.36.0-py3-none-any.whl", hash = "sha256:e215c4d74e87108449838fb81f60875f3811772f645aa0455753d74069395dec", size = 224246, upload-time = "2026-04-10T00:41:03.741Z" }, + { url = "https://files.pythonhosted.org/packages/bb/0f/752b2e140568e05d6a11619265a1941f00d25ab98f0c6669017fd86c51c9/google_cloud_dlp-3.33.0-py3-none-any.whl", hash = "sha256:982220c5ae66b93724ef008286ccc7baef33d975b4b1d62f715a2678424a757b", size = 218631, upload-time = "2025-10-17T02:32:46.326Z" }, ] [[package]] name = "google-cloud-language" -version = "2.20.0" +version = "2.18.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1295,14 +1228,14 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/d2/06ba73d3ec41b7db89ac3650b2af6a2511f02f5de6612f128c90874abb51/google_cloud_language-2.20.0.tar.gz", hash = "sha256:32844e562f7f15e9f8136186913c818513e1f40c3bd685ddd44c3b5b2855dc93", size = 187620, upload-time = "2026-03-26T22:17:14.223Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/ed/59445dde0a3a575ef901c82f07b40bb39056e17e122bae5cc4049b19938c/google_cloud_language-2.18.0.tar.gz", hash = "sha256:75b9535f6b424c9c08fe1ef5d7cce42932591a80da73a1da72c591dfdc69c41e", size = 178780, upload-time = "2025-10-17T02:34:57.766Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/5a/94fa67bb276c19dc2bff2b4cfdbfb6746a0238cdbb986c0cf9d17b5a1023/google_cloud_language-2.20.0-py3-none-any.whl", hash = "sha256:c290c2f6debde9e874523d03b7fdf1cef699f7360605829b087ea71be34f3988", size = 175372, upload-time = "2026-03-26T22:13:49.079Z" }, + { url = "https://files.pythonhosted.org/packages/c1/94/64c5e9ae6b312c8034a159ab8e7103a02866dbab1cbe0f76a2b3c3229150/google_cloud_language-2.18.0-py3-none-any.whl", hash = "sha256:d803dd6b10e3696d8bb11ce93a89ff17957e8d1666b1547f86e50867fef1854c", size = 168878, upload-time = "2025-10-17T02:33:15.834Z" }, ] [[package]] name = "google-cloud-logging" -version = "3.15.0" +version = "3.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1311,35 +1244,18 @@ dependencies = [ { name = "google-cloud-audit-log" }, { name = "google-cloud-core" }, { name = "grpc-google-iam-v1" }, - { name = "grpcio" }, { name = "opentelemetry-api" }, { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/06/253e9795a5877f35183a7175977ca47a17255fe0c8487155f48b86c83f3e/google_cloud_logging-3.15.0.tar.gz", hash = "sha256:72168a1e98bbfc27c75f0b8f630a7f5d786065f3f1f7e9e53d2d787a03693a4a", size = 294881, upload-time = "2026-03-26T22:18:36.947Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/0c/fc1a0c57f95d21559ed13e381d9024e9ee9d521489707573fd10af856545/google_cloud_logging-3.15.0-py3-none-any.whl", hash = "sha256:7dcc67434c4e7181510c133d5ac8fd4ce60c23fa4158661f67e54bf440c32450", size = 234212, upload-time = "2026-03-26T22:15:16.404Z" }, -] - -[[package]] -name = "google-cloud-monitoring" -version = "2.30.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpcio" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/3f/7bc306ebb006114f58fb9143aec91e1b014a11577350d8bbd6bbc38389f9/google_cloud_monitoring-2.30.0.tar.gz", hash = "sha256:a9530aa9aa246c490810dfa7be32d67e8340d19108acc99cbc02d1ed494fba76", size = 407108, upload-time = "2026-03-26T22:17:10.365Z" } +sdist = { url = "https://files.pythonhosted.org/packages/14/9c/d42ecc94f795a6545930e5f846a7ae59ff685ded8bc086648dd2bee31a1a/google_cloud_logging-3.12.1.tar.gz", hash = "sha256:36efc823985055b203904e83e1c8f9f999b3c64270bcda39d57386ca4effd678", size = 289569, upload-time = "2025-04-22T20:50:24.71Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/c8/666c21c470b9d6fd62ac9ee74dc265419975228f9b16f8ad72ec22e8d98b/google_cloud_monitoring-2.30.0-py3-none-any.whl", hash = "sha256:2729f3b88a4798b7757b1d9d31b6cb562bb3544e8173765e4e5cd44d8685b1ed", size = 391367, upload-time = "2026-03-26T22:15:04.088Z" }, + { url = "https://files.pythonhosted.org/packages/b1/41/f8a3197d39b773a91f335dee36c92ef26a8ec96efe78d64baad89d367df4/google_cloud_logging-3.12.1-py2.py3-none-any.whl", hash = "sha256:6817878af76ec4e7568976772839ab2c43ddfd18fbbf2ce32b13ef549cd5a862", size = 229466, upload-time = "2025-04-22T20:50:23.294Z" }, ] [[package]] name = "google-cloud-pipeline-components" -version = "2.22.0" +version = "2.21.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core" }, @@ -1348,12 +1264,12 @@ dependencies = [ { name = "kfp" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/ab/72e202d05f4bf0c286dbda91be67689417b90c4d45431fdae58772da4956/google_cloud_pipeline_components-2.22.0-py3-none-any.whl", hash = "sha256:aea2d526b3d562246beb7a4ca983e48983448c7b8b04a4f7053374f08a927104", size = 1386885, upload-time = "2025-11-10T23:26:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/fe/fe/9d572ad5a0d83a8bace621cce2fec4e00b1e60774e245124c41f25614ec3/google_cloud_pipeline_components-2.21.0-py3-none-any.whl", hash = "sha256:33d967541e726cae5466d2e46ca7d1c6e411b8d29a94a296fda13a6d75f9097d", size = 1466141, upload-time = "2025-09-25T21:44:46.235Z" }, ] [[package]] name = "google-cloud-pubsub" -version = "2.37.0" +version = "2.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1366,14 +1282,14 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/89/558c48382d6875335ea6cd7f6409acfbf256b9f7fbc2ad1c19976aabdb1f/google_cloud_pubsub-2.37.0.tar.gz", hash = "sha256:7c5ba9beb5236e2b83c091dd6171423dc7d6d0e989391bd09f60dbd242b29f10", size = 403391, upload-time = "2026-04-10T00:41:17.799Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/dd/6e016dc4c893b8a7eee9f5a4ca8659a886164580bfb129b744f47aff1cde/google_cloud_pubsub-2.33.0.tar.gz", hash = "sha256:83bc50c54f669efb924ad21385bc7092fa11f7576eabef3d0b4d7aa8efa90aa6", size = 393962, upload-time = "2025-10-30T20:13:08.226Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/f1/bb7162ec50971b1d252e6837d05f64f185d5cfe4e08de8f706e363c305d9/google_cloud_pubsub-2.37.0-py3-none-any.whl", hash = "sha256:dd912422cf66e4ffb423b0d5391ca81bdfa408eb0f21f57adecdb6fb3b1e0bb1", size = 325136, upload-time = "2026-04-10T00:41:01.391Z" }, + { url = "https://files.pythonhosted.org/packages/5b/35/6f341d8b2e94cb61b6ead415e582e3fd697472ccef9bc3972c6d83e6273f/google_cloud_pubsub-2.33.0-py3-none-any.whl", hash = "sha256:d7af3b6448c9adc171f677a989dafb4c67df6112140bd4633f4bf7e3ebe67aa0", size = 321254, upload-time = "2025-10-30T20:13:06.37Z" }, ] [[package]] name = "google-cloud-pubsublite" -version = "1.13.0" +version = "1.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1383,9 +1299,9 @@ dependencies = [ { name = "overrides" }, { name = "proto-plus" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e0/80/e494008d190bc8147d456839fbb996d0639bf4aefd47c189ac8454d96486/google_cloud_pubsublite-1.13.0.tar.gz", hash = "sha256:cc56ca57755e7665a66f0c0025ca923f7bfeb39ba408859ffe87cb840c0e82b5", size = 287447, upload-time = "2025-12-16T14:01:41.879Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/61/e41160faf2d0348dc4b45e44ace5215395cba61cd7a733ad41a48e7dea03/google_cloud_pubsublite-1.12.0.tar.gz", hash = "sha256:9ab65255ddbb313f46babd510b0eaa3ebd54532b7e99eead948d76e1d28a6f1b", size = 285887, upload-time = "2025-02-24T22:55:07.648Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/69/b95c2cc498c327d2e0c515ff70c72c4a6605099f4738c039fddb6a132928/google_cloud_pubsublite-1.13.0-py3-none-any.whl", hash = "sha256:00773be42f335ec0e76e0e3e6c72041c2795268433f48add29780cea41e8bd3e", size = 324080, upload-time = "2025-12-16T14:01:40.825Z" }, + { url = "https://files.pythonhosted.org/packages/74/a2/858881a04f708f3aa5e782ce79ca8b283ed12f9a4c55c8401ef9810b8d12/google_cloud_pubsublite-1.12.0-py2.py3-none-any.whl", hash = "sha256:5c013ebdc3bdee53979f3ca78e331118e58e145dc7c062415b1b60825ceb5625", size = 322029, upload-time = "2025-02-24T22:55:05.39Z" }, ] [[package]] @@ -1405,7 +1321,7 @@ wheels = [ [[package]] name = "google-cloud-resource-manager" -version = "1.17.0" +version = "1.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1415,33 +1331,27 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/1a/13060cabf553d52d151d2afc26b39561e82853380d499dd525a0d422d9f0/google_cloud_resource_manager-1.17.0.tar.gz", hash = "sha256:0f486b62e2c58ff992a3a50fa0f4a96eef7750aa6c971bb373398ccb91828660", size = 464971, upload-time = "2026-03-26T22:17:29.204Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/19/b95d0e8814ce42522e434cdd85c0cb6236d874d9adf6685fc8e6d1fda9d1/google_cloud_resource_manager-1.15.0.tar.gz", hash = "sha256:3d0b78c3daa713f956d24e525b35e9e9a76d597c438837171304d431084cedaf", size = 449227, upload-time = "2025-10-20T14:57:01.108Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/661d7a9023e877a226b5683429c3662f75a29ef45cb1464cf39adb689218/google_cloud_resource_manager-1.17.0-py3-none-any.whl", hash = "sha256:e479baf4b014a57f298e01b8279e3290b032e3476d69c8e5e1427af8f82739a5", size = 404403, upload-time = "2026-03-26T22:15:26.57Z" }, + { url = "https://files.pythonhosted.org/packages/8c/93/5aef41a5f146ad4559dd7040ae5fa8e7ddcab4dfadbef6cb4b66d775e690/google_cloud_resource_manager-1.15.0-py3-none-any.whl", hash = "sha256:0ccde5db644b269ddfdf7b407a2c7b60bdbf459f8e666344a5285601d00c7f6d", size = 397151, upload-time = "2025-10-20T14:53:45.409Z" }, ] [[package]] name = "google-cloud-spanner" -version = "3.65.0" +version = "3.59.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, { name = "google-cloud-core" }, - { name = "google-cloud-monitoring" }, { name = "grpc-google-iam-v1" }, { name = "grpc-interceptor" }, - { name = "mmh3" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-resourcedetector-gcp" }, - { name = "opentelemetry-sdk" }, - { name = "opentelemetry-semantic-conventions" }, { name = "proto-plus" }, { name = "protobuf" }, { name = "sqlparse" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/90/b3e3c9c7b1a5ebc76d780fcda58e3a27208d5a10c6c5b78fab64dc5ea5f9/google_cloud_spanner-3.65.0.tar.gz", hash = "sha256:434139bd1439528398cd2a96e390a57182420747c214a33f317bbac64afd9c5c", size = 889154, upload-time = "2026-04-13T22:14:34.416Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/62/f0e535875e49b34128710342115681fe1a97f45759e1427307ab150a4caa/google_cloud_spanner-3.59.0.tar.gz", hash = "sha256:dec7a78bfe1f94aef508ff9c61dba4196f3c70c83a0f75c271b4652686d08641", size = 705137, upload-time = "2025-10-23T09:35:49.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/c6/0f0806253de7e1ef5943a9e30df7798c0f5dd6e840707a899975e17d4c60/google_cloud_spanner-3.65.0-py3-none-any.whl", hash = "sha256:67ca892698d9530d10c682be7c38265089088b57272af3e57f1ea7afb9e88eff", size = 614036, upload-time = "2026-04-13T22:14:32.533Z" }, + { url = "https://files.pythonhosted.org/packages/d8/08/1a38139853364b4737e3a0e03a3fd87d60c7545e90a963a8a6457777b5f9/google_cloud_spanner-3.59.0-py3-none-any.whl", hash = "sha256:409ed9746787c9435fd015731a5e3cf6f3ea2995a807c580f4216bb5d464260a", size = 502645, upload-time = "2025-10-23T09:35:47.954Z" }, ] [[package]] @@ -1463,7 +1373,7 @@ wheels = [ [[package]] name = "google-cloud-videointelligence" -version = "2.19.0" +version = "2.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1472,14 +1382,14 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/af/a1d11dc04a694f58536523c7f0cd266dff454b29b610fc57bf85afc1733f/google_cloud_videointelligence-2.19.0.tar.gz", hash = "sha256:7b320c18a0475b08dde9b60a0fbfdf8915320c20966159fad80b5594089d561e", size = 259738, upload-time = "2026-03-26T22:18:30.163Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/c3/039548b7e7a1589c3f816065014a4dddceb9ba33bf5e8b6666b1e6d609ce/google_cloud_videointelligence-2.17.0.tar.gz", hash = "sha256:0008b4e618e3ea835883e032d8660c86c6b933c98fe0bfadda036086ff037284", size = 243662, upload-time = "2025-10-20T14:57:32.816Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/4f/6ae7b3f9c81c70ecf08fd56dee17356add4730e708620312d0caf5eb2d06/google_cloud_videointelligence-2.19.0-py3-none-any.whl", hash = "sha256:b11b04c2643a50dfb030c8ae16b0f50746319c986d3570f46a6b4e16bb0b1b5b", size = 288236, upload-time = "2026-03-26T22:13:21.662Z" }, + { url = "https://files.pythonhosted.org/packages/3f/56/d19ef7a2d3f669568046e68ce980c5091e037bdd960d3dae44854bbba437/google_cloud_videointelligence-2.17.0-py3-none-any.whl", hash = "sha256:b294a7e09a0154c02dcaa250e93686a57b76736ba448bd5033692679b6585cf6", size = 276733, upload-time = "2025-10-20T14:55:32.306Z" }, ] [[package]] name = "google-cloud-vision" -version = "3.13.0" +version = "3.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -1488,45 +1398,43 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1c/f9/208ae25a03f822fcc7f762198cdedaefdbac4f923f72e5c39d3bdbf2ec60/google_cloud_vision-3.13.0.tar.gz", hash = "sha256:680f668d331858a3340eac41b732903d30dc69ed08020ffd1d5ca32580bdf546", size = 592075, upload-time = "2026-03-26T22:18:38.206Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/83/8a5de5968933671badfffd1738eac489b29c557274d97191a4acbe0a5d9a/google_cloud_vision-3.11.0.tar.gz", hash = "sha256:c3cb57df2cf152ebe62ebaae9b1d5deff5a26aec5bd6e1c7f67e44bf6f4518f4", size = 570943, upload-time = "2025-10-20T14:57:34.107Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/74/775192dc2a930191e821c5cd841d399576ae7bca4db98ee5cc262ac56de0/google_cloud_vision-3.13.0-py3-none-any.whl", hash = "sha256:f6979e93ad60a7e556b152de2857f7d3b9b740afd022cea1c76548ef80c29b87", size = 543152, upload-time = "2026-03-26T22:13:13.127Z" }, + { url = "https://files.pythonhosted.org/packages/cc/ca/8c5ff6041a081a6271159b2e5d378be69c964da75191ff79ef241c6ccbb3/google_cloud_vision-3.11.0-py3-none-any.whl", hash = "sha256:8910f743a87a34058dd6e5e41790be1eb100a0b91c20cc6372a2388b328c8890", size = 529092, upload-time = "2025-10-20T14:55:33.756Z" }, ] [[package]] name = "google-crc32c" -version = "1.8.0" +version = "1.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/ae/87802e6d9f9d69adfaedfcfd599266bf386a54d0be058b532d04c794f76d/google_crc32c-1.7.1.tar.gz", hash = "sha256:2bff2305f98846f3e825dbeec9ee406f89da7962accdb29356e4eadc251bd472", size = 14495, upload-time = "2025-03-26T14:29:13.32Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/ef/21ccfaab3d5078d41efe8612e0ed0bfc9ce22475de074162a91a25f7980d/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8", size = 31298, upload-time = "2025-12-16T00:20:32.241Z" }, - { url = "https://files.pythonhosted.org/packages/c5/b8/f8413d3f4b676136e965e764ceedec904fe38ae8de0cdc52a12d8eb1096e/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7", size = 30872, upload-time = "2025-12-16T00:33:58.785Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15", size = 33243, upload-time = "2025-12-16T00:40:21.46Z" }, - { url = "https://files.pythonhosted.org/packages/71/03/4820b3bd99c9653d1a5210cb32f9ba4da9681619b4d35b6a052432df4773/google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a", size = 33608, upload-time = "2025-12-16T00:40:22.204Z" }, - { url = "https://files.pythonhosted.org/packages/7c/43/acf61476a11437bf9733fb2f70599b1ced11ec7ed9ea760fdd9a77d0c619/google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2", size = 34439, upload-time = "2025-12-16T00:35:20.458Z" }, - { url = "https://files.pythonhosted.org/packages/52/c5/c171e4d8c44fec1422d801a6d2e5d7ddabd733eeda505c79730ee9607f07/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93", size = 28615, upload-time = "2025-12-16T00:40:29.298Z" }, - { url = "https://files.pythonhosted.org/packages/9c/97/7d75fe37a7a6ed171a2cf17117177e7aab7e6e0d115858741b41e9dd4254/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c", size = 28800, upload-time = "2025-12-16T00:40:30.322Z" }, + { url = "https://files.pythonhosted.org/packages/f7/94/220139ea87822b6fdfdab4fb9ba81b3fff7ea2c82e2af34adc726085bffc/google_crc32c-1.7.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:6fbab4b935989e2c3610371963ba1b86afb09537fd0c633049be82afe153ac06", size = 30468, upload-time = "2025-03-26T14:32:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/94/97/789b23bdeeb9d15dc2904660463ad539d0318286d7633fe2760c10ed0c1c/google_crc32c-1.7.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:ed66cbe1ed9cbaaad9392b5259b3eba4a9e565420d734e6238813c428c3336c9", size = 30313, upload-time = "2025-03-26T14:57:38.758Z" }, + { url = "https://files.pythonhosted.org/packages/81/b8/976a2b843610c211e7ccb3e248996a61e87dbb2c09b1499847e295080aec/google_crc32c-1.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee6547b657621b6cbed3562ea7826c3e11cab01cd33b74e1f677690652883e77", size = 33048, upload-time = "2025-03-26T14:41:30.679Z" }, + { url = "https://files.pythonhosted.org/packages/c9/16/a3842c2cf591093b111d4a5e2bfb478ac6692d02f1b386d2a33283a19dc9/google_crc32c-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d68e17bad8f7dd9a49181a1f5a8f4b251c6dbc8cc96fb79f1d321dfd57d66f53", size = 32669, upload-time = "2025-03-26T14:41:31.432Z" }, + { url = "https://files.pythonhosted.org/packages/04/17/ed9aba495916fcf5fe4ecb2267ceb851fc5f273c4e4625ae453350cfd564/google_crc32c-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:6335de12921f06e1f774d0dd1fbea6bf610abe0887a1638f64d694013138be5d", size = 33476, upload-time = "2025-03-26T14:29:10.211Z" }, + { url = "https://files.pythonhosted.org/packages/16/1b/1693372bf423ada422f80fd88260dbfd140754adb15cbc4d7e9a68b1cb8e/google_crc32c-1.7.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85fef7fae11494e747c9fd1359a527e5970fc9603c90764843caabd3a16a0a48", size = 28241, upload-time = "2025-03-26T14:41:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/fd/3c/2a19a60a473de48717b4efb19398c3f914795b64a96cf3fbe82588044f78/google_crc32c-1.7.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6efb97eb4369d52593ad6f75e7e10d053cf00c48983f7a973105bc70b0ac4d82", size = 28048, upload-time = "2025-03-26T14:41:46.696Z" }, ] [[package]] name = "google-genai" -version = "1.73.1" +version = "1.47.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, - { name = "distro" }, - { name = "google-auth", extra = ["requests"] }, + { name = "google-auth" }, { name = "httpx" }, { name = "pydantic" }, { name = "requests" }, - { name = "sniffio" }, { name = "tenacity" }, { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/d8/40f5f107e5a2976bbac52d421f04d14fc221b55a8f05e66be44b2f739fe6/google_genai-1.73.1.tar.gz", hash = "sha256:b637e3a3b9e2eccc46f27136d470165803de84eca52abfed2e7352081a4d5a15", size = 530998, upload-time = "2026-04-14T21:06:19.153Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/97/784fba9bc6c41263ff90cb9063eadfdd755dde79cfa5a8d0e397b067dcf9/google_genai-1.47.0.tar.gz", hash = "sha256:ecece00d0a04e6739ea76cc8dad82ec9593d9380aaabef078990e60574e5bf59", size = 241471, upload-time = "2025-10-29T22:01:02.88Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/af/508e0528015240d710c6763f7c89ff44fab9a94a80b4377e265d692cbfd6/google_genai-1.73.1-py3-none-any.whl", hash = "sha256:af2d2287d25e42a187de19811ef33beb2e347c7e2bdb4dc8c467d78254e43a2c", size = 783595, upload-time = "2026-04-14T21:06:17.464Z" }, + { url = "https://files.pythonhosted.org/packages/89/ef/e080e8d67c270ea320956bb911a9359664fc46d3b87d1f029decd33e5c4c/google_genai-1.47.0-py3-none-any.whl", hash = "sha256:e3851237556cbdec96007d8028b4b1f2425cdc5c099a8dc36b72a57e42821b60", size = 241506, upload-time = "2025-10-29T22:01:00.982Z" }, ] [[package]] @@ -1543,26 +1451,26 @@ wheels = [ [[package]] name = "google-resumable-media" -version = "2.8.2" +version = "2.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-crc32c" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/d1/b1ea14b93b6b78f57fc580125de44e9f593ab88dd2460f1a8a8d18f74754/google_resumable_media-2.8.2.tar.gz", hash = "sha256:f3354a182ebd193ae3f42e3ef95e6c9b10f128320de23ac7637236713b1acd70", size = 2164510, upload-time = "2026-03-30T23:34:25.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/5a/0efdc02665dca14e0837b62c8a1a93132c264bd02054a15abb2218afe0ae/google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0", size = 2163099, upload-time = "2024-08-07T22:20:38.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/f8/50bfaf4658431ff9de45c5c3935af7ab01157a4903c603cd0eee6e78e087/google_resumable_media-2.8.2-py3-none-any.whl", hash = "sha256:82b6d8ccd11765268cdd2a2123f417ec806b8eef3000a9a38dfe3033da5fb220", size = 81511, upload-time = "2026-03-30T23:34:09.671Z" }, + { url = "https://files.pythonhosted.org/packages/82/35/b8d3baf8c46695858cb9d8835a53baa1eeb9906ddaf2f728a5f5b640fd1e/google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa", size = 81251, upload-time = "2024-08-07T22:20:36.409Z" }, ] [[package]] name = "googleapis-common-protos" -version = "1.74.0" +version = "1.71.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/18/a746c8344152d368a5aac738d4c857012f2c5d1fd2eac7e17b647a7861bd/googleapis_common_protos-1.74.0.tar.gz", hash = "sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1", size = 151254, upload-time = "2026-04-02T21:23:26.679Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/43/b25abe02db2911397819003029bef768f68a974f2ece483e6084d1a5f754/googleapis_common_protos-1.71.0.tar.gz", hash = "sha256:1aec01e574e29da63c80ba9f7bbf1ccfaacf1da877f23609fe236ca7c72a2e2e", size = 146454, upload-time = "2025-10-20T14:58:08.732Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/b0/be5d3329badb9230b765de6eea66b73abd5944bdeb5afb3562ddcd80ae84/googleapis_common_protos-1.74.0-py3-none-any.whl", hash = "sha256:702216f78610bb510e3f12ac3cafd281b7ac45cc5d86e90ad87e4d301a3426b5", size = 300743, upload-time = "2026-04-02T21:22:49.108Z" }, + { url = "https://files.pythonhosted.org/packages/25/e8/eba9fece11d57a71e3e22ea672742c8f3cf23b35730c9e96db768b295216/googleapis_common_protos-1.71.0-py3-none-any.whl", hash = "sha256:59034a1d849dc4d18971997a72ac56246570afdd17f9369a0ff68218d50ab78c", size = 294576, upload-time = "2025-10-20T14:56:21.295Z" }, ] [package.optional-dependencies] @@ -1572,34 +1480,35 @@ grpc = [ [[package]] name = "greenlet" -version = "3.4.0" +version = "3.2.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/94/a5935717b307d7c71fe877b52b884c6af707d2d2090db118a03fbd799369/greenlet-3.4.0.tar.gz", hash = "sha256:f50a96b64dafd6169e595a5c56c9146ef80333e67d4476a65a9c55f400fc22ff", size = 195913, upload-time = "2026-04-08T17:08:00.863Z" } +sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/c6/dba32cab7e3a625b011aa5647486e2d28423a48845a2998c126dd69c85e1/greenlet-3.4.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:805bebb4945094acbab757d34d6e1098be6de8966009ab9ca54f06ff492def58", size = 285504, upload-time = "2026-04-08T15:52:14.071Z" }, - { url = "https://files.pythonhosted.org/packages/54/f4/7cb5c2b1feb9a1f50e038be79980dfa969aa91979e5e3a18fdbcfad2c517/greenlet-3.4.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:439fc2f12b9b512d9dfa681c5afe5f6b3232c708d13e6f02c845e0d9f4c2d8c6", size = 605476, upload-time = "2026-04-08T16:24:37.064Z" }, - { url = "https://files.pythonhosted.org/packages/d6/af/b66ab0b2f9a4c5a867c136bf66d9599f34f21a1bcca26a2884a29c450bd9/greenlet-3.4.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a70ed1cb0295bee1df57b63bf7f46b4e56a5c93709eea769c1fec1bb23a95875", size = 618336, upload-time = "2026-04-08T16:30:56.59Z" }, - { url = "https://files.pythonhosted.org/packages/6d/31/56c43d2b5de476f77d36ceeec436328533bff960a4cba9a07616e93063ab/greenlet-3.4.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c5696c42e6bb5cfb7c6ff4453789081c66b9b91f061e5e9367fa15792644e76", size = 625045, upload-time = "2026-04-08T16:40:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/e5/5c/8c5633ece6ba611d64bf2770219a98dd439921d6424e4e8cf16b0ac74ea5/greenlet-3.4.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c660bce1940a1acae5f51f0a064f1bc785d07ea16efcb4bc708090afc4d69e83", size = 613515, upload-time = "2026-04-08T15:56:32.478Z" }, - { url = "https://files.pythonhosted.org/packages/80/ca/704d4e2c90acb8bdf7ae593f5cbc95f58e82de95cc540fb75631c1054533/greenlet-3.4.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:89995ce5ddcd2896d89615116dd39b9703bfa0c07b583b85b89bf1b5d6eddf81", size = 419745, upload-time = "2026-04-08T16:43:04.022Z" }, - { url = "https://files.pythonhosted.org/packages/a9/df/950d15bca0d90a0e7395eb777903060504cdb509b7b705631e8fb69ff415/greenlet-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ee407d4d1ca9dc632265aee1c8732c4a2d60adff848057cdebfe5fe94eb2c8a2", size = 1574623, upload-time = "2026-04-08T16:26:18.596Z" }, - { url = "https://files.pythonhosted.org/packages/1a/e7/0839afab829fcb7333c9ff6d80c040949510055d2d4d63251f0d1c7c804e/greenlet-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:956215d5e355fffa7c021d168728321fd4d31fd730ac609b1653b450f6a4bc71", size = 1639579, upload-time = "2026-04-08T15:57:29.231Z" }, - { url = "https://files.pythonhosted.org/packages/d9/2b/b4482401e9bcaf9f5c97f67ead38db89c19520ff6d0d6699979c6efcc200/greenlet-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:5cb614ace7c27571270354e9c9f696554d073f8aa9319079dcba466bbdead711", size = 238233, upload-time = "2026-04-08T17:02:54.286Z" }, - { url = "https://files.pythonhosted.org/packages/0c/4d/d8123a4e0bcd583d5cfc8ddae0bbe29c67aab96711be331a7cc935a35966/greenlet-3.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:04403ac74fe295a361f650818de93be11b5038a78f49ccfb64d3b1be8fbf1267", size = 235045, upload-time = "2026-04-08T17:04:05.072Z" }, + { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" }, + { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646, upload-time = "2025-08-07T13:45:26.523Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519, upload-time = "2025-08-07T13:53:13.928Z" }, + { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707, upload-time = "2025-08-07T13:18:27.146Z" }, + { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" }, + { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" }, + { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" }, + { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385, upload-time = "2025-11-04T12:42:11.067Z" }, + { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329, upload-time = "2025-11-04T12:42:12.928Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" }, ] [[package]] name = "grpc-google-iam-v1" -version = "0.14.4" +version = "0.14.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos", extra = ["grpc"] }, { name = "grpcio" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/4f/d098419ad0bfc06c9ce440575f05aa22d8973b6c276e86ac7890093d3c37/grpc_google_iam_v1-0.14.4.tar.gz", hash = "sha256:392b3796947ed6334e61171d9ab06bf7eb357f554e5fc7556ad7aab6d0e17038", size = 23706, upload-time = "2026-04-01T01:57:49.813Z" } +sdist = { url = "https://files.pythonhosted.org/packages/76/1e/1011451679a983f2f5c6771a1682542ecb027776762ad031fd0d7129164b/grpc_google_iam_v1-0.14.3.tar.gz", hash = "sha256:879ac4ef33136c5491a6300e27575a9ec760f6cdf9a2518798c1b8977a5dc389", size = 23745, upload-time = "2025-10-15T21:14:53.318Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/22/c2dd50c09bf679bd38173656cd4402d2511e563b33bc88f90009cf50613c/grpc_google_iam_v1-0.14.4-py3-none-any.whl", hash = "sha256:412facc320fcbd94034b4df3d557662051d4d8adfa86e0ddb4dca70a3f739964", size = 32675, upload-time = "2026-04-01T01:57:47.69Z" }, + { url = "https://files.pythonhosted.org/packages/4a/bd/330a1bbdb1afe0b96311249e699b6dc9cfc17916394fd4503ac5aca2514b/grpc_google_iam_v1-0.14.3-py3-none-any.whl", hash = "sha256:7a7f697e017a067206a3dfef44e4c634a34d3dee135fe7d7a4613fe3e59217e6", size = 32690, upload-time = "2025-10-15T21:14:51.72Z" }, ] [[package]] @@ -1616,23 +1525,23 @@ wheels = [ [[package]] name = "grpcio" -version = "1.80.0" +version = "1.76.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/e0/318c1ce3ae5a17894d5791e87aea147587c9e702f24122cc7a5c8bbaeeb1/grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73", size = 12785182, upload-time = "2025-10-21T16:23:12.106Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/db/1d56e5f5823257b291962d6c0ce106146c6447f405b60b234c4f222a7cde/grpcio-1.80.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a", size = 6055009, upload-time = "2026-03-30T08:46:46.265Z" }, - { url = "https://files.pythonhosted.org/packages/6e/18/c83f3cad64c5ca63bca7e91e5e46b0d026afc5af9d0a9972472ceba294b3/grpcio-1.80.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060", size = 12035295, upload-time = "2026-03-30T08:46:49.099Z" }, - { url = "https://files.pythonhosted.org/packages/0f/8e/e14966b435be2dda99fbe89db9525ea436edc79780431a1c2875a3582644/grpcio-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2", size = 6610297, upload-time = "2026-03-30T08:46:52.123Z" }, - { url = "https://files.pythonhosted.org/packages/cc/26/d5eb38f42ce0e3fdc8174ea4d52036ef8d58cc4426cb800f2610f625dd75/grpcio-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21", size = 7300208, upload-time = "2026-03-30T08:46:54.859Z" }, - { url = "https://files.pythonhosted.org/packages/25/51/bd267c989f85a17a5b3eea65a6feb4ff672af41ca614e5a0279cc0ea381c/grpcio-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab", size = 6813442, upload-time = "2026-03-30T08:46:57.056Z" }, - { url = "https://files.pythonhosted.org/packages/9e/d9/d80eef735b19e9169e30164bbf889b46f9df9127598a83d174eb13a48b26/grpcio-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1", size = 7414743, upload-time = "2026-03-30T08:46:59.682Z" }, - { url = "https://files.pythonhosted.org/packages/de/f2/567f5bd5054398ed6b0509b9a30900376dcf2786bd936812098808b49d8d/grpcio-1.80.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106", size = 8426046, upload-time = "2026-03-30T08:47:02.474Z" }, - { url = "https://files.pythonhosted.org/packages/62/29/73ef0141b4732ff5eacd68430ff2512a65c004696997f70476a83e548e7e/grpcio-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6", size = 7851641, upload-time = "2026-03-30T08:47:05.462Z" }, - { url = "https://files.pythonhosted.org/packages/46/69/abbfa360eb229a8623bab5f5a4f8105e445bd38ce81a89514ba55d281ad0/grpcio-1.80.0-cp311-cp311-win32.whl", hash = "sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440", size = 4154368, upload-time = "2026-03-30T08:47:08.027Z" }, - { url = "https://files.pythonhosted.org/packages/6f/d4/ae92206d01183b08613e846076115f5ac5991bae358d2a749fa864da5699/grpcio-1.80.0-cp311-cp311-win_amd64.whl", hash = "sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9", size = 4894235, upload-time = "2026-03-30T08:47:10.839Z" }, + { url = "https://files.pythonhosted.org/packages/a0/00/8163a1beeb6971f66b4bbe6ac9457b97948beba8dd2fc8e1281dce7f79ec/grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a", size = 5843567, upload-time = "2025-10-21T16:20:52.829Z" }, + { url = "https://files.pythonhosted.org/packages/10/c1/934202f5cf335e6d852530ce14ddb0fef21be612ba9ecbbcbd4d748ca32d/grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c", size = 11848017, upload-time = "2025-10-21T16:20:56.705Z" }, + { url = "https://files.pythonhosted.org/packages/11/0b/8dec16b1863d74af6eb3543928600ec2195af49ca58b16334972f6775663/grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465", size = 6412027, upload-time = "2025-10-21T16:20:59.3Z" }, + { url = "https://files.pythonhosted.org/packages/d7/64/7b9e6e7ab910bea9d46f2c090380bab274a0b91fb0a2fe9b0cd399fffa12/grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48", size = 7075913, upload-time = "2025-10-21T16:21:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/093c46e9546073cefa789bd76d44c5cb2abc824ca62af0c18be590ff13ba/grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da", size = 6615417, upload-time = "2025-10-21T16:21:03.844Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b6/5709a3a68500a9c03da6fb71740dcdd5ef245e39266461a03f31a57036d8/grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397", size = 7199683, upload-time = "2025-10-21T16:21:06.195Z" }, + { url = "https://files.pythonhosted.org/packages/91/d3/4b1f2bf16ed52ce0b508161df3a2d186e4935379a159a834cb4a7d687429/grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749", size = 8163109, upload-time = "2025-10-21T16:21:08.498Z" }, + { url = "https://files.pythonhosted.org/packages/5c/61/d9043f95f5f4cf085ac5dd6137b469d41befb04bd80280952ffa2a4c3f12/grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00", size = 7626676, upload-time = "2025-10-21T16:21:10.693Z" }, + { url = "https://files.pythonhosted.org/packages/36/95/fd9a5152ca02d8881e4dd419cdd790e11805979f499a2e5b96488b85cf27/grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054", size = 3997688, upload-time = "2025-10-21T16:21:12.746Z" }, + { url = "https://files.pythonhosted.org/packages/60/9c/5c359c8d4c9176cfa3c61ecd4efe5affe1f38d9bae81e81ac7186b4c9cc8/grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d", size = 4709315, upload-time = "2025-10-21T16:21:15.26Z" }, ] [[package]] @@ -1660,21 +1569,21 @@ wheels = [ [[package]] name = "h5py" -version = "3.16.0" +version = "3.15.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/db/33/acd0ce6863b6c0d7735007df01815403f5589a21ff8c2e1ee2587a38f548/h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738", size = 446526, upload-time = "2026-03-06T13:49:08.07Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/6a/0d79de0b025aa85dc8864de8e97659c94cf3d23148394a954dc5ca52f8c8/h5py-3.15.1.tar.gz", hash = "sha256:c86e3ed45c4473564de55aa83b6fc9e5ead86578773dfbd93047380042e26b69", size = 426236, upload-time = "2025-10-16T10:35:27.404Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/95/a825894f3e45cbac7554c4e97314ce886b233a20033787eda755ca8fecc7/h5py-3.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:719439d14b83f74eeb080e9650a6c7aa6d0d9ea0ca7f804347b05fac6fbf18af", size = 3721663, upload-time = "2026-03-06T13:47:49.599Z" }, - { url = "https://files.pythonhosted.org/packages/bf/3b/38ff88b347c3e346cda1d3fc1b65a7aa75d40632228d8b8a5d7b58508c24/h5py-3.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3f0a0e136f2e95dd0b67146abb6668af4f1a69c81ef8651a2d316e8e01de447", size = 3087630, upload-time = "2026-03-06T13:47:51.249Z" }, - { url = "https://files.pythonhosted.org/packages/98/a8/2594cef906aee761601eff842c7dc598bea2b394a3e1c00966832b8eeb7c/h5py-3.16.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a6fbc5367d4046801f9b7db9191b31895f22f1c6df1f9987d667854cac493538", size = 4823472, upload-time = "2026-03-06T13:47:53.085Z" }, - { url = "https://files.pythonhosted.org/packages/52/a0/c1f604538ff6db22a0690be2dc44ab59178e115f63c917794e529356ab23/h5py-3.16.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fb1720028d99040792bb2fb31facb8da44a6f29df7697e0b84f0d79aff2e9bd3", size = 5027150, upload-time = "2026-03-06T13:47:55.043Z" }, - { url = "https://files.pythonhosted.org/packages/2e/fd/301739083c2fc4fd89950f9bcfce75d6e14b40b0ca3d40e48a8993d1722c/h5py-3.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:314b6054fe0b1051c2b0cb2df5cbdab15622fb05e80f202e3b6a5eee0d6fe365", size = 4814544, upload-time = "2026-03-06T13:47:56.893Z" }, - { url = "https://files.pythonhosted.org/packages/4c/42/2193ed41ccee78baba8fcc0cff2c925b8b9ee3793305b23e1f22c20bf4c7/h5py-3.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ffbab2fedd6581f6aa31cf1639ca2cb86e02779de525667892ebf4cc9fd26434", size = 5034013, upload-time = "2026-03-06T13:47:59.01Z" }, - { url = "https://files.pythonhosted.org/packages/f7/20/e6c0ff62ca2ad1a396a34f4380bafccaaf8791ff8fccf3d995a1fc12d417/h5py-3.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d1f1630f92ad74494a9a7392ab25982ce2b469fc62da6074c0ce48366a2999", size = 3191673, upload-time = "2026-03-06T13:48:00.626Z" }, - { url = "https://files.pythonhosted.org/packages/f2/48/239cbe352ac4f2b8243a8e620fa1a2034635f633731493a7ff1ed71e8658/h5py-3.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:85b9c49dd58dc44cf70af944784e2c2038b6f799665d0dcbbc812a26e0faa859", size = 2673834, upload-time = "2026-03-06T13:48:02.579Z" }, + { url = "https://files.pythonhosted.org/packages/41/fd/8349b48b15b47768042cff06ad6e1c229f0a4bd89225bf6b6894fea27e6d/h5py-3.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5aaa330bcbf2830150c50897ea5dcbed30b5b6d56897289846ac5b9e529ec243", size = 3434135, upload-time = "2025-10-16T10:33:47.954Z" }, + { url = "https://files.pythonhosted.org/packages/c1/b0/1c628e26a0b95858f54aba17e1599e7f6cd241727596cc2580b72cb0a9bf/h5py-3.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c970fb80001fffabb0109eaf95116c8e7c0d3ca2de854e0901e8a04c1f098509", size = 2870958, upload-time = "2025-10-16T10:33:50.907Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e3/c255cafc9b85e6ea04e2ad1bba1416baa1d7f57fc98a214be1144087690c/h5py-3.15.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80e5bb5b9508d5d9da09f81fd00abbb3f85da8143e56b1585d59bc8ceb1dba8b", size = 4504770, upload-time = "2025-10-16T10:33:54.357Z" }, + { url = "https://files.pythonhosted.org/packages/8b/23/4ab1108e87851ccc69694b03b817d92e142966a6c4abd99e17db77f2c066/h5py-3.15.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b849ba619a066196169763c33f9f0f02e381156d61c03e000bb0100f9950faf", size = 4700329, upload-time = "2025-10-16T10:33:57.616Z" }, + { url = "https://files.pythonhosted.org/packages/a4/e4/932a3a8516e4e475b90969bf250b1924dbe3612a02b897e426613aed68f4/h5py-3.15.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e7f6c841efd4e6e5b7e82222eaf90819927b6d256ab0f3aca29675601f654f3c", size = 4152456, upload-time = "2025-10-16T10:34:00.843Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0a/f74d589883b13737021b2049ac796328f188dbb60c2ed35b101f5b95a3fc/h5py-3.15.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ca8a3a22458956ee7b40d8e39c9a9dc01f82933e4c030c964f8b875592f4d831", size = 4617295, upload-time = "2025-10-16T10:34:04.154Z" }, + { url = "https://files.pythonhosted.org/packages/23/95/499b4e56452ef8b6c95a271af0dde08dac4ddb70515a75f346d4f400579b/h5py-3.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:550e51131376889656feec4aff2170efc054a7fe79eb1da3bb92e1625d1ac878", size = 2882129, upload-time = "2025-10-16T10:34:06.886Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bb/cfcc70b8a42222ba3ad4478bcef1791181ea908e2adbd7d53c66395edad5/h5py-3.15.1-cp311-cp311-win_arm64.whl", hash = "sha256:b39239947cb36a819147fc19e86b618dcb0953d1cd969f5ed71fc0de60392427", size = 2477121, upload-time = "2025-10-16T10:34:09.579Z" }, ] [[package]] @@ -1744,41 +1653,41 @@ wheels = [ [[package]] name = "identify" -version = "2.6.19" +version = "2.6.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, ] [[package]] name = "idna" -version = "3.13" +version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] name = "imagesize" -version = "2.0.0" +version = "1.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/e6/7bf14eeb8f8b7251141944835abd42eb20a658d89084b7e1f3e5fe394090/imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3", size = 1773045, upload-time = "2026-03-03T14:18:29.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" }, + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, ] [[package]] name = "importlib-metadata" -version = "8.7.1" +version = "8.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, + { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, ] [[package]] @@ -1786,15 +1695,15 @@ name = "iopath" version = "0.1.10" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "portalocker" }, - { name = "tqdm" }, - { name = "typing-extensions" }, + { name = "portalocker", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tqdm", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/73/b3d451dfc523756cf177d3ebb0af76dc7751b341c60e2a21871be400ae29/iopath-0.1.10.tar.gz", hash = "sha256:3311c16a4d9137223e20f141655759933e1eda24f8bff166af834af3c645ef01", size = 42226, upload-time = "2022-07-09T19:00:50.866Z" } [[package]] name = "ipykernel" -version = "7.2.0" +version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "appnope", marker = "sys_platform == 'darwin' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, @@ -1811,14 +1720,14 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e", size = 176046, upload-time = "2026-02-06T16:43:27.403Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/b9/e73d5d9f405cba7706c539aa8b311b49d4c2f3d698d9c12f815231169c71/ipykernel-7.2.0-py3-none-any.whl", hash = "sha256:3bbd4420d2b3cc105cbdf3756bfc04500b1e52f090a90716851f3916c62e1661", size = 118788, upload-time = "2026-02-06T16:43:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, ] [[package]] name = "ipython" -version = "9.13.0" +version = "9.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, @@ -1828,15 +1737,14 @@ dependencies = [ { name = "matplotlib-inline" }, { name = "pexpect", marker = "(sys_platform != 'emscripten' and sys_platform != 'win32') or (sys_platform == 'emscripten' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform == 'win32' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, { name = "prompt-toolkit" }, - { name = "psutil" }, { name = "pygments" }, { name = "stack-data" }, { name = "traitlets" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/87cda5842cf5c31837c06ddb588e11c3c35d8ece89b7a0108c06b8c9b00a/ipython-9.13.0.tar.gz", hash = "sha256:7e834b6afc99f020e3f05966ced34792f40267d64cb1ea9043886dab0dde5967", size = 4430549, upload-time = "2026-04-24T12:24:55.221Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/34/29b18c62e39ee2f7a6a3bba7efd952729d8aadd45ca17efc34453b717665/ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731", size = 4396932, upload-time = "2025-09-29T10:55:53.948Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/86/3060e8029b7cc505cce9a0137431dda81d0a3fde93a8f0f50ee0bf37a795/ipython-9.13.0-py3-none-any.whl", hash = "sha256:57f9d4639e20818d328d287c7b549af3d05f12486ea8f2e7f73e52a36ec4d201", size = 627274, upload-time = "2026-04-24T12:24:53.038Z" }, + { url = "https://files.pythonhosted.org/packages/48/c5/d5e07995077e48220269c28a221e168c91123ad5ceee44d548f54a057fc0/ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196", size = 616170, upload-time = "2025-09-29T10:55:47.676Z" }, ] [[package]] @@ -1877,11 +1785,11 @@ wheels = [ [[package]] name = "joblib" -version = "1.5.3" +version = "1.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, ] [[package]] @@ -1909,7 +1817,7 @@ wheels = [ [[package]] name = "jsonschema" -version = "4.26.0" +version = "4.25.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -1917,9 +1825,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, ] [[package]] @@ -1955,7 +1863,7 @@ wheels = [ [[package]] name = "jupyter-client" -version = "8.8.0" +version = "8.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-core" }, @@ -1964,9 +1872,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020, upload-time = "2026-01-08T13:55:47.938Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371, upload-time = "2026-01-08T13:55:45.562Z" }, + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, ] [[package]] @@ -1993,7 +1901,7 @@ wheels = [ [[package]] name = "keras" -version = "3.14.0" +version = "3.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "absl-py" }, @@ -2005,9 +1913,9 @@ dependencies = [ { name = "packaging" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/88/ce/47874047a49eedc2a5d3b41bc4f1f572bb637f51e4351ef3538e49a63800/keras-3.14.0.tar.gz", hash = "sha256:86fcf8249a25264a566ac393c287c7ad657000e5e62615dcaad4b3472a17aeda", size = 1263098, upload-time = "2026-04-03T01:42:16.386Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/b8/8df141314a64a31d3a21762658826f716cdf4c261c7fcdb3f729958def55/keras-3.12.0.tar.gz", hash = "sha256:536e3f8385a05ae04e82e08715a1a59988578087e187b04cb0a6fad11743f07f", size = 1129187, upload-time = "2025-10-27T20:23:11.574Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/20/78d26f81115d570bdf0e57d19b81de9ad8aa55ddb68eb10c8f0699fccb63/keras-3.14.0-py3-none-any.whl", hash = "sha256:19ce94b798caaba4d404ab6ef4753b44219170e5c2868156de8bb0494a260114", size = 1627362, upload-time = "2026-04-03T01:42:11.606Z" }, + { url = "https://files.pythonhosted.org/packages/ba/61/cc8be27bd65082440754be443b17b6f7c185dec5e00dfdaeab4f8662e4a8/keras-3.12.0-py3-none-any.whl", hash = "sha256:02b69e007d5df8042286c3bcc2a888539e3e487590ffb08f6be1b4354df50aa8", size = 1474424, upload-time = "2025-10-27T20:23:09.571Z" }, ] [[package]] @@ -2056,30 +1964,28 @@ sdist = { url = "https://files.pythonhosted.org/packages/c0/5c/10c7cd96cee27da45 [[package]] name = "kiwisolver" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/dd/a495a9c104be1c476f0386e714252caf2b7eca883915422a64c50b88c6f5/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c", size = 122798, upload-time = "2026-03-09T13:12:58.963Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb", size = 66216, upload-time = "2026-03-09T13:13:00.155Z" }, - { url = "https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac", size = 63911, upload-time = "2026-03-09T13:13:01.671Z" }, - { url = "https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27", size = 1438209, upload-time = "2026-03-09T13:13:03.385Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d6/76621246f5165e5372f02f5e6f3f48ea336a8f9e96e43997d45b240ed8cd/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398", size = 1248888, upload-time = "2026-03-09T13:13:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c1/31559ec6fb39a5b48035ce29bb63ade628f321785f38c384dee3e2c08bc1/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db", size = 1266304, upload-time = "2026-03-09T13:13:06.743Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ef/1cb8276f2d29cc6a41e0a042f27946ca347d3a4a75acf85d0a16aa6dcc82/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc", size = 1319650, upload-time = "2026-03-09T13:13:08.607Z" }, - { url = "https://files.pythonhosted.org/packages/4c/e4/5ba3cecd7ce6236ae4a80f67e5d5531287337d0e1f076ca87a5abe4cd5d0/kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679", size = 970949, upload-time = "2026-03-09T13:13:10.299Z" }, - { url = "https://files.pythonhosted.org/packages/5a/69/dc61f7ae9a2f071f26004ced87f078235b5507ab6e5acd78f40365655034/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309", size = 2199125, upload-time = "2026-03-09T13:13:11.841Z" }, - { url = "https://files.pythonhosted.org/packages/e5/7b/abbe0f1b5afa85f8d084b73e90e5f801c0939eba16ac2e49af7c61a6c28d/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2", size = 2293783, upload-time = "2026-03-09T13:13:14.399Z" }, - { url = "https://files.pythonhosted.org/packages/8a/80/5908ae149d96d81580d604c7f8aefd0e98f4fd728cf172f477e9f2a81744/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c", size = 1960726, upload-time = "2026-03-09T13:13:16.047Z" }, - { url = "https://files.pythonhosted.org/packages/84/08/a78cb776f8c085b7143142ce479859cfec086bd09ee638a317040b6ef420/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08", size = 2464738, upload-time = "2026-03-09T13:13:17.897Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e1/65584da5356ed6cb12c63791a10b208860ac40a83de165cb6a6751a686e3/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4", size = 2270718, upload-time = "2026-03-09T13:13:19.421Z" }, - { url = "https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b", size = 73480, upload-time = "2026-03-09T13:13:20.818Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0e/2ee5debc4f77a625778fec5501ff3e8036fe361b7ee28ae402a485bb9694/kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac", size = 64930, upload-time = "2026-03-09T13:13:21.997Z" }, - { url = "https://files.pythonhosted.org/packages/e9/eb/5fcbbbf9a0e2c3a35effb88831a483345326bbc3a030a3b5b69aee647f84/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232", size = 59532, upload-time = "2026-03-09T13:15:47.047Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9b/e17104555bb4db148fd52327feea1e96be4b88e8e008b029002c281a21ab/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a", size = 57420, upload-time = "2026-03-09T13:15:48.199Z" }, - { url = "https://files.pythonhosted.org/packages/48/44/2b5b95b7aa39fb2d8d9d956e0f3d5d45aef2ae1d942d4c3ffac2f9cfed1a/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737", size = 79892, upload-time = "2026-03-09T13:15:49.694Z" }, - { url = "https://files.pythonhosted.org/packages/52/7d/7157f9bba6b455cfb4632ed411e199fc8b8977642c2b12082e1bd9e6d173/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16", size = 77603, upload-time = "2026-03-09T13:15:50.945Z" }, - { url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" }, +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167, upload-time = "2025-08-10T21:25:53.403Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579, upload-time = "2025-08-10T21:25:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309, upload-time = "2025-08-10T21:25:55.76Z" }, + { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596, upload-time = "2025-08-10T21:25:56.861Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548, upload-time = "2025-08-10T21:25:58.246Z" }, + { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618, upload-time = "2025-08-10T21:25:59.857Z" }, + { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437, upload-time = "2025-08-10T21:26:01.105Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742, upload-time = "2025-08-10T21:26:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810, upload-time = "2025-08-10T21:26:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579, upload-time = "2025-08-10T21:26:05.317Z" }, + { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071, upload-time = "2025-08-10T21:26:06.686Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840, upload-time = "2025-08-10T21:26:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159, upload-time = "2025-08-10T21:26:09.048Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104, upload-time = "2025-08-10T21:27:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592, upload-time = "2025-08-10T21:27:44.314Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281, upload-time = "2025-08-10T21:27:45.369Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009, upload-time = "2025-08-10T21:27:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929, upload-time = "2025-08-10T21:27:48.236Z" }, ] [[package]] @@ -2122,24 +2028,25 @@ wheels = [ [[package]] name = "lightning-utilities" -version = "0.15.3" +version = "0.15.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "packaging" }, - { name = "typing-extensions" }, + { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "setuptools", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f1/45/7fa8f56b17dc0f0a41ec70dd307ecd6787254483549843bef4c30ab5adce/lightning_utilities-0.15.3.tar.gz", hash = "sha256:792ae0204c79f6859721ac7f386c237a33b0ed06ba775009cb894e010a842033", size = 33553, upload-time = "2026-02-22T14:48:53.348Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/39/6fc58ca81492db047149b4b8fd385aa1bfb8c28cd7cacb0c7eb0c44d842f/lightning_utilities-0.15.2.tar.gz", hash = "sha256:cdf12f530214a63dacefd713f180d1ecf5d165338101617b4742e8f22c032e24", size = 31090, upload-time = "2025-08-06T13:57:39.242Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/f4/ead6e0e37209b07c9baa3e984ccdb0348ca370b77cea3aaea8ddbb097e00/lightning_utilities-0.15.3-py3-none-any.whl", hash = "sha256:6c55f1bee70084a1cbeaa41ada96e4b3a0fea5909e844dd335bd80f5a73c5f91", size = 31906, upload-time = "2026-02-22T14:48:52.488Z" }, + { url = "https://files.pythonhosted.org/packages/de/73/3d757cb3fc16f0f9794dd289bcd0c4a031d9cf54d8137d6b984b2d02edf3/lightning_utilities-0.15.2-py3-none-any.whl", hash = "sha256:ad3ab1703775044bbf880dbf7ddaaac899396c96315f3aa1779cec9d618a9841", size = 29431, upload-time = "2025-08-06T13:57:38.046Z" }, ] [[package]] name = "markdown" -version = "3.10.2" +version = "3.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, ] [[package]] @@ -2175,7 +2082,7 @@ wheels = [ [[package]] name = "matplotlib" -version = "3.10.9" +version = "3.10.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy" }, @@ -2188,18 +2095,18 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/e2/d2d5295be2f44c678ebaf3544ba32d20c1f9ef08c49fe47f496180e1db15/matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7", size = 34804865, upload-time = "2025-10-09T00:28:00.669Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:68cfdcede415f7c8f5577b03303dd94526cdb6d11036cecdc205e08733b2d2bb", size = 8306860, upload-time = "2026-04-24T00:12:01.207Z" }, - { url = "https://files.pythonhosted.org/packages/51/18/325cd32ece1120d1da51cc4e4294c6580190699490183fc2fe8cb6d61ec5/matplotlib-3.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfca0129678bd56379db26c52b5d77ed7de314c047492fbdc763aa7501710cfb", size = 8199254, upload-time = "2026-04-24T00:12:04.239Z" }, - { url = "https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e436d155fa8a3399dc62683f8f5d0e2e50d25d0144a73edd73f82eec8f4abfb", size = 8777092, upload-time = "2026-04-24T00:12:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/55/fa/3ce7adfe9ba101748f465211660d9c6374c876b671bdb8c2bb6d347e8b94/matplotlib-3.10.9-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56fc0bd271b00025c6edfdc7c2dcd247372c8e1544971d62e1dc7c17367e8bf9", size = 9595691, upload-time = "2026-04-24T00:12:09.706Z" }, - { url = "https://files.pythonhosted.org/packages/36/c4/6960a76686ed668f2c60f84e9799ba4c0d56abdb36b1577b60c1d061d1ec/matplotlib-3.10.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5a6104ed666402ba5106d7f36e0e0cdca4e8d7fa4d39708ca88019e2835a2eb", size = 9659771, upload-time = "2026-04-24T00:12:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:d730e984eddf56974c3e72b6129c7ca462ac38dc624338f4b0b23eb23ecba00f", size = 8205112, upload-time = "2026-04-24T00:12:15.773Z" }, - { url = "https://files.pythonhosted.org/packages/e2/ee/cb57ad4754f3e7b9174ce6ce66d9205fb827067e48a9f58ac09d7e7d6b77/matplotlib-3.10.9-cp311-cp311-win_arm64.whl", hash = "sha256:51bf0ddbdc598e060d46c16b5590708f81a1624cefbaaf62f6a81bf9285b8c80", size = 8132310, upload-time = "2026-04-24T00:12:18.645Z" }, - { url = "https://files.pythonhosted.org/packages/63/e2/9f66ca6a651a52abfe0d4964ce01439ed34f3f1e119de10ff3a07f403043/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:42fb814efabe95c06c1994d8ab5a8385f43a249e23badd3ba931d4308e5bca20", size = 8304420, upload-time = "2026-04-24T00:14:04.57Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e8/467c03568218792906aa87b5e7bb379b605e056ed0c74fe00c051786d925/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f76e640a5268850bfda54b5131b1b1941cc685e42c5fa98ed9f2d64038308cba", size = 8197981, upload-time = "2026-04-24T00:14:07.233Z" }, - { url = "https://files.pythonhosted.org/packages/6f/87/afead29192170917537934c6aff4b008c805fff7b1ccea0c79120d96beda/matplotlib-3.10.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3fc0364dfbe1d07f6d15c5ebd0c5bf89e126916e5a8667dd4a7a6e84c36653d4", size = 8774002, upload-time = "2026-04-24T00:14:09.816Z" }, + { url = "https://files.pythonhosted.org/packages/fc/bc/0fb489005669127ec13f51be0c6adc074d7cf191075dab1da9fe3b7a3cfc/matplotlib-3.10.7-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:53b492410a6cd66c7a471de6c924f6ede976e963c0f3097a3b7abfadddc67d0a", size = 8257507, upload-time = "2025-10-09T00:26:19.073Z" }, + { url = "https://files.pythonhosted.org/packages/e2/6a/d42588ad895279ff6708924645b5d2ed54a7fb2dc045c8a804e955aeace1/matplotlib-3.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d9749313deb729f08207718d29c86246beb2ea3fdba753595b55901dee5d2fd6", size = 8119565, upload-time = "2025-10-09T00:26:21.023Z" }, + { url = "https://files.pythonhosted.org/packages/10/b7/4aa196155b4d846bd749cf82aa5a4c300cf55a8b5e0dfa5b722a63c0f8a0/matplotlib-3.10.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2222c7ba2cbde7fe63032769f6eb7e83ab3227f47d997a8453377709b7fe3a5a", size = 8692668, upload-time = "2025-10-09T00:26:22.967Z" }, + { url = "https://files.pythonhosted.org/packages/e6/e7/664d2b97016f46683a02d854d730cfcf54ff92c1dafa424beebef50f831d/matplotlib-3.10.7-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e91f61a064c92c307c5a9dc8c05dc9f8a68f0a3be199d9a002a0622e13f874a1", size = 9521051, upload-time = "2025-10-09T00:26:25.041Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a3/37aef1404efa615f49b5758a5e0261c16dd88f389bc1861e722620e4a754/matplotlib-3.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6f1851eab59ca082c95df5a500106bad73672645625e04538b3ad0f69471ffcc", size = 9576878, upload-time = "2025-10-09T00:26:27.478Z" }, + { url = "https://files.pythonhosted.org/packages/33/cd/b145f9797126f3f809d177ca378de57c45413c5099c5990de2658760594a/matplotlib-3.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:6516ce375109c60ceec579e699524e9d504cd7578506f01150f7a6bc174a775e", size = 8115142, upload-time = "2025-10-09T00:26:29.774Z" }, + { url = "https://files.pythonhosted.org/packages/2e/39/63bca9d2b78455ed497fcf51a9c71df200a11048f48249038f06447fa947/matplotlib-3.10.7-cp311-cp311-win_arm64.whl", hash = "sha256:b172db79759f5f9bc13ef1c3ef8b9ee7b37b0247f987fbbbdaa15e4f87fd46a9", size = 7992439, upload-time = "2025-10-09T00:26:40.32Z" }, + { url = "https://files.pythonhosted.org/packages/58/8f/76d5dc21ac64a49e5498d7f0472c0781dae442dd266a67458baec38288ec/matplotlib-3.10.7-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15112bcbaef211bd663fa935ec33313b948e214454d949b723998a43357b17b0", size = 8252283, upload-time = "2025-10-09T00:27:54.739Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/9c5d4c2317feb31d819e38c9f947c942f42ebd4eb935fc6fd3518a11eaa7/matplotlib-3.10.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d2a959c640cdeecdd2ec3136e8ea0441da59bcaf58d67e9c590740addba2cb68", size = 8116733, upload-time = "2025-10-09T00:27:56.406Z" }, + { url = "https://files.pythonhosted.org/packages/9a/cc/3fe688ff1355010937713164caacf9ed443675ac48a997bab6ed23b3f7c0/matplotlib-3.10.7-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3886e47f64611046bc1db523a09dd0a0a6bed6081e6f90e13806dd1d1d1b5e91", size = 8693919, upload-time = "2025-10-09T00:27:58.41Z" }, ] [[package]] @@ -2262,11 +2169,11 @@ wheels = [ [[package]] name = "mistune" -version = "3.2.0" +version = "3.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/02/a7fb8b21d4d55ac93cdcde9d3638da5dd0ebdd3a4fed76c7725e10b81cbe/mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164", size = 94588, upload-time = "2025-08-29T07:20:43.594Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, + { url = "https://files.pythonhosted.org/packages/7a/f0/8282d9641415e9e33df173516226b404d367a0fc55e1a60424a152913abc/mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d", size = 53481, upload-time = "2025-08-29T07:20:42.218Z" }, ] [[package]] @@ -2286,26 +2193,26 @@ wheels = [ [[package]] name = "mmh3" -version = "5.2.1" +version = "5.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/1a/edb23803a168f070ded7a3014c6d706f63b90c84ccc024f89d794a3b7a6d/mmh3-5.2.1.tar.gz", hash = "sha256:bbea5b775f0ac84945191fb83f845a6fd9a21a03ea7f2e187defac7e401616ad", size = 33775, upload-time = "2026-03-05T15:55:57.716Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/af/f28c2c2f51f31abb4725f9a64bc7863d5f491f6539bd26aee2a1d21a649e/mmh3-5.2.0.tar.gz", hash = "sha256:1efc8fec8478e9243a78bb993422cf79f8ff85cb4cf6b79647480a31e0d950a8", size = 33582, upload-time = "2025-07-29T07:43:48.49Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/d7/3312a59df3c1cdd783f4cf0c4ee8e9decff9c5466937182e4cc7dbbfe6c5/mmh3-5.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae0f0bd7d30c0ad61b9a504e8e272cb8391eed3f1587edf933f4f6b33437450", size = 56082, upload-time = "2026-03-05T15:53:59.702Z" }, - { url = "https://files.pythonhosted.org/packages/61/96/6f617baa098ca0d2989bfec6d28b5719532cd8d8848782662f5b755f657f/mmh3-5.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9aeaf53eaa075dd63e81512522fd180097312fb2c9f476333309184285c49ce0", size = 40458, upload-time = "2026-03-05T15:54:01.548Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b4/9cd284bd6062d711e13d26c04d4778ab3f690c1c38a4563e3c767ec8802e/mmh3-5.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0634581290e6714c068f4aa24020acf7880927d1f0084fa753d9799ae9610082", size = 40079, upload-time = "2026-03-05T15:54:02.743Z" }, - { url = "https://files.pythonhosted.org/packages/f6/09/a806334ce1d3d50bf782b95fcee8b3648e1e170327d4bb7b4bad2ad7d956/mmh3-5.2.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e080c0637aea036f35507e803a4778f119a9b436617694ae1c5c366805f1e997", size = 97242, upload-time = "2026-03-05T15:54:04.536Z" }, - { url = "https://files.pythonhosted.org/packages/ee/93/723e317dd9e041c4dc4566a2eb53b01ad94de31750e0b834f1643905e97c/mmh3-5.2.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db0562c5f71d18596dcd45e854cf2eeba27d7543e1a3acdafb7eef728f7fe85d", size = 103082, upload-time = "2026-03-05T15:54:06.387Z" }, - { url = "https://files.pythonhosted.org/packages/61/b5/f96121e69cc48696075071531cf574f112e1ffd08059f4bffb41210e6fc5/mmh3-5.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d9f9a3ce559a5267014b04b82956993270f63ec91765e13e9fd73daf2d2738e", size = 106054, upload-time = "2026-03-05T15:54:07.506Z" }, - { url = "https://files.pythonhosted.org/packages/82/49/192b987ec48d0b2aecf8ac285a9b11fbc00030f6b9c694664ae923458dde/mmh3-5.2.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:960b1b3efa39872ac8b6cc3a556edd6fb90ed74f08c9c45e028f1005b26aa55d", size = 112910, upload-time = "2026-03-05T15:54:09.403Z" }, - { url = "https://files.pythonhosted.org/packages/cf/a1/03e91fd334ed0144b83343a76eb11f17434cd08f746401488cfeafb2d241/mmh3-5.2.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d30b650595fdbe32366b94cb14f30bb2b625e512bd4e1df00611f99dc5c27fd4", size = 120551, upload-time = "2026-03-05T15:54:10.587Z" }, - { url = "https://files.pythonhosted.org/packages/93/b9/b89a71d2ff35c3a764d1c066c7313fc62c7cc48fa48a4b3b0304a4a0146f/mmh3-5.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:82f3802bfc4751f420d591c5c864de538b71cea117fce67e4595c2afede08a15", size = 99096, upload-time = "2026-03-05T15:54:11.76Z" }, - { url = "https://files.pythonhosted.org/packages/36/b5/613772c1c6ed5f7b63df55eb131e887cc43720fec392777b95a79d34e640/mmh3-5.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:915e7a2418f10bd1151b1953df06d896db9783c9cfdb9a8ee1f9b3a4331ab503", size = 98524, upload-time = "2026-03-05T15:54:13.122Z" }, - { url = "https://files.pythonhosted.org/packages/5e/0e/1524566fe8eaf871e4f7bc44095929fcd2620488f402822d848df19d679c/mmh3-5.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fc78739b5ec6e4fb02301984a3d442a91406e7700efbe305071e7fd1c78278f2", size = 106239, upload-time = "2026-03-05T15:54:14.601Z" }, - { url = "https://files.pythonhosted.org/packages/04/94/21adfa7d90a7a697137ad6de33eeff6445420ca55e433a5d4919c79bc3b5/mmh3-5.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:41aac7002a749f08727cb91babff1daf8deac317c0b1f317adc69be0e6c375d1", size = 109797, upload-time = "2026-03-05T15:54:15.819Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e6/1aacc3a219e1aa62fa65669995d4a3562b35be5200ec03680c7e4bec9676/mmh3-5.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9d8089d853c7963a8ce87fff93e2a67075c0bc08684a08ea6ad13577c38ffc38", size = 97228, upload-time = "2026-03-05T15:54:16.992Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b9/5e4cca8dcccf298add0a27f3c357bc8cf8baf821d35cdc6165e4bd5a48b0/mmh3-5.2.1-cp311-cp311-win32.whl", hash = "sha256:baeb47635cb33375dee4924cd93d7f5dcaa786c740b08423b0209b824a1ee728", size = 40751, upload-time = "2026-03-05T15:54:18.714Z" }, - { url = "https://files.pythonhosted.org/packages/72/fc/5b11d49247f499bcda591171e9cf3b6ee422b19e70aa2cef2e0ae65ca3b9/mmh3-5.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1e4ecee40ba19e6975e1120829796770325841c2f153c0e9aecca927194c6a2a", size = 41517, upload-time = "2026-03-05T15:54:19.764Z" }, - { url = "https://files.pythonhosted.org/packages/8a/5f/2a511ee8a1c2a527c77726d5231685b72312c5a1a1b7639ad66a9652aa84/mmh3-5.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:c302245fd6c33d96bd169c7ccf2513c20f4c1e417c07ce9dce107c8bc3f8411f", size = 39287, upload-time = "2026-03-05T15:54:20.904Z" }, + { url = "https://files.pythonhosted.org/packages/f7/87/399567b3796e134352e11a8b973cd470c06b2ecfad5468fe580833be442b/mmh3-5.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7901c893e704ee3c65f92d39b951f8f34ccf8e8566768c58103fb10e55afb8c1", size = 56107, upload-time = "2025-07-29T07:41:57.07Z" }, + { url = "https://files.pythonhosted.org/packages/c3/09/830af30adf8678955b247d97d3d9543dd2fd95684f3cd41c0cd9d291da9f/mmh3-5.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5f5536b1cbfa72318ab3bfc8a8188b949260baed186b75f0abc75b95d8c051", size = 40635, upload-time = "2025-07-29T07:41:57.903Z" }, + { url = "https://files.pythonhosted.org/packages/07/14/eaba79eef55b40d653321765ac5e8f6c9ac38780b8a7c2a2f8df8ee0fb72/mmh3-5.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cedac4f4054b8f7859e5aed41aaa31ad03fce6851901a7fdc2af0275ac533c10", size = 40078, upload-time = "2025-07-29T07:41:58.772Z" }, + { url = "https://files.pythonhosted.org/packages/bb/26/83a0f852e763f81b2265d446b13ed6d49ee49e1fc0c47b9655977e6f3d81/mmh3-5.2.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eb756caf8975882630ce4e9fbbeb9d3401242a72528230422c9ab3a0d278e60c", size = 97262, upload-time = "2025-07-29T07:41:59.678Z" }, + { url = "https://files.pythonhosted.org/packages/00/7d/b7133b10d12239aeaebf6878d7eaf0bf7d3738c44b4aba3c564588f6d802/mmh3-5.2.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:097e13c8b8a66c5753c6968b7640faefe85d8e38992703c1f666eda6ef4c3762", size = 103118, upload-time = "2025-07-29T07:42:01.197Z" }, + { url = "https://files.pythonhosted.org/packages/7b/3e/62f0b5dce2e22fd5b7d092aba285abd7959ea2b17148641e029f2eab1ffa/mmh3-5.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7c0c7845566b9686480e6a7e9044db4afb60038d5fabd19227443f0104eeee4", size = 106072, upload-time = "2025-07-29T07:42:02.601Z" }, + { url = "https://files.pythonhosted.org/packages/66/84/ea88bb816edfe65052c757a1c3408d65c4201ddbd769d4a287b0f1a628b2/mmh3-5.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:61ac226af521a572700f863d6ecddc6ece97220ce7174e311948ff8c8919a363", size = 112925, upload-time = "2025-07-29T07:42:03.632Z" }, + { url = "https://files.pythonhosted.org/packages/2e/13/c9b1c022807db575fe4db806f442d5b5784547e2e82cff36133e58ea31c7/mmh3-5.2.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:582f9dbeefe15c32a5fa528b79b088b599a1dfe290a4436351c6090f90ddebb8", size = 120583, upload-time = "2025-07-29T07:42:04.991Z" }, + { url = "https://files.pythonhosted.org/packages/8a/5f/0e2dfe1a38f6a78788b7eb2b23432cee24623aeabbc907fed07fc17d6935/mmh3-5.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2ebfc46b39168ab1cd44670a32ea5489bcbc74a25795c61b6d888c5c2cf654ed", size = 99127, upload-time = "2025-07-29T07:42:05.929Z" }, + { url = "https://files.pythonhosted.org/packages/77/27/aefb7d663b67e6a0c4d61a513c83e39ba2237e8e4557fa7122a742a23de5/mmh3-5.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1556e31e4bd0ac0c17eaf220be17a09c171d7396919c3794274cb3415a9d3646", size = 98544, upload-time = "2025-07-29T07:42:06.87Z" }, + { url = "https://files.pythonhosted.org/packages/ab/97/a21cc9b1a7c6e92205a1b5fa030cdf62277d177570c06a239eca7bd6dd32/mmh3-5.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81df0dae22cd0da87f1c978602750f33d17fb3d21fb0f326c89dc89834fea79b", size = 106262, upload-time = "2025-07-29T07:42:07.804Z" }, + { url = "https://files.pythonhosted.org/packages/43/18/db19ae82ea63c8922a880e1498a75342311f8aa0c581c4dd07711473b5f7/mmh3-5.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:eba01ec3bd4a49b9ac5ca2bc6a73ff5f3af53374b8556fcc2966dd2af9eb7779", size = 109824, upload-time = "2025-07-29T07:42:08.735Z" }, + { url = "https://files.pythonhosted.org/packages/9f/f5/41dcf0d1969125fc6f61d8618b107c79130b5af50b18a4651210ea52ab40/mmh3-5.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e9a011469b47b752e7d20de296bb34591cdfcbe76c99c2e863ceaa2aa61113d2", size = 97255, upload-time = "2025-07-29T07:42:09.706Z" }, + { url = "https://files.pythonhosted.org/packages/32/b3/cce9eaa0efac1f0e735bb178ef9d1d2887b4927fe0ec16609d5acd492dda/mmh3-5.2.0-cp311-cp311-win32.whl", hash = "sha256:bc44fc2b886243d7c0d8daeb37864e16f232e5b56aaec27cc781d848264cfd28", size = 40779, upload-time = "2025-07-29T07:42:10.546Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e9/3fa0290122e6d5a7041b50ae500b8a9f4932478a51e48f209a3879fe0b9b/mmh3-5.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:8ebf241072cf2777a492d0e09252f8cc2b3edd07dfdb9404b9757bffeb4f2cee", size = 41549, upload-time = "2025-07-29T07:42:11.399Z" }, + { url = "https://files.pythonhosted.org/packages/3a/54/c277475b4102588e6f06b2e9095ee758dfe31a149312cdbf62d39a9f5c30/mmh3-5.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5f317a727bba0e633a12e71228bc6a4acb4f471a98b1c003163b917311ea9a9", size = 39336, upload-time = "2025-07-29T07:42:12.209Z" }, ] [[package]] @@ -2336,29 +2243,29 @@ wheels = [ [[package]] name = "multidict" -version = "6.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, - { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, - { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, - { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, - { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, - { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, - { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, - { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, - { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, - { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, - { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, - { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, - { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, - { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, - { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +version = "6.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604, upload-time = "2025-10-06T14:48:54.277Z" }, + { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715, upload-time = "2025-10-06T14:48:55.445Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332, upload-time = "2025-10-06T14:48:56.706Z" }, + { url = "https://files.pythonhosted.org/packages/31/61/0c2d50241ada71ff61a79518db85ada85fdabfcf395d5968dae1cbda04e5/multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c", size = 245212, upload-time = "2025-10-06T14:48:58.042Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e0/919666a4e4b57fff1b57f279be1c9316e6cdc5de8a8b525d76f6598fefc7/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7", size = 246671, upload-time = "2025-10-06T14:49:00.004Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cc/d027d9c5a520f3321b65adea289b965e7bcbd2c34402663f482648c716ce/multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7", size = 225491, upload-time = "2025-10-06T14:49:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/75/c4/bbd633980ce6155a28ff04e6a6492dd3335858394d7bb752d8b108708558/multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9", size = 257322, upload-time = "2025-10-06T14:49:02.745Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6d/d622322d344f1f053eae47e033b0b3f965af01212de21b10bcf91be991fb/multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8", size = 254694, upload-time = "2025-10-06T14:49:04.15Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9f/78f8761c2705d4c6d7516faed63c0ebdac569f6db1bef95e0d5218fdc146/multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd", size = 246715, upload-time = "2025-10-06T14:49:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/950818e04f91b9c2b95aab3d923d9eabd01689d0dcd889563988e9ea0fd8/multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb", size = 243189, upload-time = "2025-10-06T14:49:07.37Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3d/77c79e1934cad2ee74991840f8a0110966d9599b3af95964c0cd79bb905b/multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6", size = 237845, upload-time = "2025-10-06T14:49:08.759Z" }, + { url = "https://files.pythonhosted.org/packages/63/1b/834ce32a0a97a3b70f86437f685f880136677ac00d8bce0027e9fd9c2db7/multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2", size = 246374, upload-time = "2025-10-06T14:49:10.574Z" }, + { url = "https://files.pythonhosted.org/packages/23/ef/43d1c3ba205b5dec93dc97f3fba179dfa47910fc73aaaea4f7ceb41cec2a/multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff", size = 253345, upload-time = "2025-10-06T14:49:12.331Z" }, + { url = "https://files.pythonhosted.org/packages/6b/03/eaf95bcc2d19ead522001f6a650ef32811aa9e3624ff0ad37c445c7a588c/multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b", size = 246940, upload-time = "2025-10-06T14:49:13.821Z" }, + { url = "https://files.pythonhosted.org/packages/e8/df/ec8a5fd66ea6cd6f525b1fcbb23511b033c3e9bc42b81384834ffa484a62/multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34", size = 242229, upload-time = "2025-10-06T14:49:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a2/59b405d59fd39ec86d1142630e9049243015a5f5291ba49cadf3c090c541/multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff", size = 41308, upload-time = "2025-10-06T14:49:16.871Z" }, + { url = "https://files.pythonhosted.org/packages/32/0f/13228f26f8b882c34da36efa776c3b7348455ec383bab4a66390e42963ae/multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81", size = 46037, upload-time = "2025-10-06T14:49:18.457Z" }, + { url = "https://files.pythonhosted.org/packages/84/1f/68588e31b000535a3207fd3c909ebeec4fb36b52c442107499c18a896a2a/multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912", size = 43023, upload-time = "2025-10-06T14:49:19.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] [[package]] @@ -2450,7 +2357,7 @@ wheels = [ [[package]] name = "nbclient" -version = "0.10.4" +version = "0.10.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-client" }, @@ -2458,14 +2365,14 @@ dependencies = [ { name = "nbformat" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424, upload-time = "2024-12-19T10:32:27.164Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, + { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434, upload-time = "2024-12-19T10:32:24.139Z" }, ] [[package]] name = "nbconvert" -version = "7.17.1" +version = "7.16.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -2483,9 +2390,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/b1/708e53fe2e429c103c6e6e159106bcf0357ac41aa4c28772bd8402339051/nbconvert-7.17.1.tar.gz", hash = "sha256:34d0d0a7e73ce3cbab6c5aae8f4f468797280b01fd8bd2ca746da8569eddd7d2", size = 865311, upload-time = "2026-04-08T00:44:14.914Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/67/f8/bb0a9d5f46819c821dc1f004aa2cc29b1d91453297dbf5ff20470f00f193/nbconvert-7.17.1-py3-none-any.whl", hash = "sha256:aa85c087b435e7bf1ffd03319f658e285f2b89eccab33bc1ba7025495ab3e7c8", size = 261927, upload-time = "2026-04-08T00:44:12.845Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, ] [[package]] @@ -2531,20 +2438,20 @@ wheels = [ [[package]] name = "networkx" -version = "3.6.1" +version = "3.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, + { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, ] [[package]] name = "nodeenv" -version = "1.10.0" +version = "1.9.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, ] [[package]] @@ -2764,57 +2671,42 @@ wheels = [ [[package]] name = "opentelemetry-api" -version = "1.41.1" +version = "1.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/fc/b7564cbef36601aef0d6c9bc01f7badb64be8e862c2e1c3c5c3b43b53e4f/opentelemetry_api-1.41.1.tar.gz", hash = "sha256:0ad1814d73b875f84494387dae86ce0b12c68556331ce6ce8fe789197c949621", size = 71416, upload-time = "2026-04-24T13:15:38.262Z" } +sdist = { url = "https://files.pythonhosted.org/packages/08/d8/0f354c375628e048bd0570645b310797299754730079853095bf000fba69/opentelemetry_api-1.38.0.tar.gz", hash = "sha256:f4c193b5e8acb0912b06ac5b16321908dd0843d75049c091487322284a3eea12", size = 65242, upload-time = "2025-10-16T08:35:50.25Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/59/3e7118ed140f76b0982ba4321bdaed1997a0473f9720de2d10788a577033/opentelemetry_api-1.41.1-py3-none-any.whl", hash = "sha256:a22df900e75c76dc08440710e51f52f1aa6b451b429298896023e60db5b3139f", size = 69007, upload-time = "2026-04-24T13:15:15.662Z" }, -] - -[[package]] -name = "opentelemetry-resourcedetector-gcp" -version = "1.11.0a0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-sdk" }, - { name = "requests" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c1/5d/2b3240d914b87b6dd9cd5ca2ef1ccaf1d0626b897d4c06877e22c8c10fcf/opentelemetry_resourcedetector_gcp-1.11.0a0.tar.gz", hash = "sha256:915a1d6fd15daca9eedd3fc52b0f705375054f2ef140e2e7a6b4cca95a47cdb1", size = 18796, upload-time = "2025-11-04T19:32:16.59Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/6c/1e13fe142a7ca3dc6489167203a1209d32430cca12775e1df9c9a41c54b2/opentelemetry_resourcedetector_gcp-1.11.0a0-py3-none-any.whl", hash = "sha256:5d65a2a039b1d40c6f41421dbb08d5f441368275ac6de6e76a8fccd1f6acb67e", size = 18798, upload-time = "2025-11-04T19:32:10.915Z" }, + { url = "https://files.pythonhosted.org/packages/ae/a2/d86e01c28300bd41bab8f18afd613676e2bd63515417b77636fc1add426f/opentelemetry_api-1.38.0-py3-none-any.whl", hash = "sha256:2891b0197f47124454ab9f0cf58f3be33faca394457ac3e09daba13ff50aa582", size = 65947, upload-time = "2025-10-16T08:35:30.23Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.41.1" +version = "1.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/d0/54ee30dab82fb0acda23d144502771ff76ef8728459c83c3e89ef9fb1825/opentelemetry_sdk-1.41.1.tar.gz", hash = "sha256:724b615e1215b5aeacda0abb8a6a8922c9a1853068948bd0bd225a56d0c792e6", size = 230180, upload-time = "2026-04-24T13:15:50.991Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/cb/f0eee1445161faf4c9af3ba7b848cc22a50a3d3e2515051ad8628c35ff80/opentelemetry_sdk-1.38.0.tar.gz", hash = "sha256:93df5d4d871ed09cb4272305be4d996236eedb232253e3ab864c8620f051cebe", size = 171942, upload-time = "2025-10-16T08:36:02.257Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/e7/a1420b698aad018e1cf60fdbaaccbe49021fb415e2a0d81c242f4c518f54/opentelemetry_sdk-1.41.1-py3-none-any.whl", hash = "sha256:edee379c126c1bce952b0c812b48fe8ff35b30df0eecf17e98afa4d598b7d85d", size = 180213, upload-time = "2026-04-24T13:15:33.767Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2e/e93777a95d7d9c40d270a371392b6d6f1ff170c2a3cb32d6176741b5b723/opentelemetry_sdk-1.38.0-py3-none-any.whl", hash = "sha256:1c66af6564ecc1553d72d811a01df063ff097cdc82ce188da9951f93b8d10f6b", size = 132349, upload-time = "2025-10-16T08:35:46.995Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.62b1" +version = "0.59b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/de/911ac9e309052aca1b20b2d5549d3db45d1011e1a610e552c6ccdd1b64f8/opentelemetry_semantic_conventions-0.62b1.tar.gz", hash = "sha256:c5cc6e04a7f8c7cdd30be2ed81499fa4e75bfbd52c9cb70d40af1f9cd3619802", size = 145750, upload-time = "2026-04-24T13:15:52.236Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/bc/8b9ad3802cd8ac6583a4eb7de7e5d7db004e89cb7efe7008f9c8a537ee75/opentelemetry_semantic_conventions-0.59b0.tar.gz", hash = "sha256:7a6db3f30d70202d5bf9fa4b69bc866ca6a30437287de6c510fb594878aed6b0", size = 129861, upload-time = "2025-10-16T08:36:03.346Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/a6/83dc2ab6fa397ee66fba04fe2e74bdf7be3b3870005359ceb7689103c058/opentelemetry_semantic_conventions-0.62b1-py3-none-any.whl", hash = "sha256:cf506938103d331fbb78eded0d9788095f7fd59016f2bda813c3324e5a74a93c", size = 231620, upload-time = "2026-04-24T13:15:35.454Z" }, + { url = "https://files.pythonhosted.org/packages/24/7d/c88d7b15ba8fe5c6b8f93be50fc11795e9fc05386c44afaf6b76fe191f9b/opentelemetry_semantic_conventions-0.59b0-py3-none-any.whl", hash = "sha256:35d3b8833ef97d614136e253c1da9342b4c3c083bbaf29ce31d572a1c3825eed", size = 207954, upload-time = "2025-10-16T08:35:48.054Z" }, ] [[package]] @@ -2828,52 +2720,50 @@ wheels = [ [[package]] name = "optree" -version = "0.19.0" +version = "0.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/63/7b078bc36d5a206c21b03565a818ede38ff0fbf014e92085ec467ef10adb/optree-0.19.0.tar.gz", hash = "sha256:bc1991a948590756409e76be4e29efd4a487a185056d35db6c67619c19ea27a1", size = 175199, upload-time = "2026-02-23T01:56:37.752Z" } +sdist = { url = "https://files.pythonhosted.org/packages/56/c7/0853e0c59b135dff770615d2713b547b6b3b5cde7c10995b4a5825244612/optree-0.17.0.tar.gz", hash = "sha256:5335a5ec44479920620d72324c66563bd705ab2a698605dd4b6ee67dbcad7ecd", size = 163111, upload-time = "2025-07-25T11:26:11.586Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/5e/5967a15ed63d98717815a51265bd73fb5ec5a4ca9938c59be909ef12f66f/optree-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e245b03f4edc90971dcf01691775105084f433393e6ba19a6fd0f151d5f39b58", size = 408515, upload-time = "2026-02-23T01:54:50.888Z" }, - { url = "https://files.pythonhosted.org/packages/43/5b/4e062008bfd2f836079afec06dd9cba76a01010aaffa8eae0d1915fa0ef6/optree-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:304ebd0449ace6ab0c18489baea1163a915b9aeb43a8635c6373ec09767fa1ba", size = 378935, upload-time = "2026-02-23T01:54:52.372Z" }, - { url = "https://files.pythonhosted.org/packages/bf/da/67424dad1834ba4bfe1ca16c1ca754e5fd32d7f8e7a488a70346c1bf1160/optree-0.19.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48366b810f0d37e2fa7bcb758d2a3198d62f0a4a60ac7e14287768345a4a95a9", size = 400165, upload-time = "2026-02-23T01:54:53.579Z" }, - { url = "https://files.pythonhosted.org/packages/65/af/f49c516de0ca47ce6a7a8f74499e63ba0a07744eae78958a2e6de0902fd6/optree-0.19.0-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:b511556fdc5a558ccd65f841710e9103f120cb575735f87ddfa3728b4098e606", size = 460863, upload-time = "2026-02-23T01:54:55.718Z" }, - { url = "https://files.pythonhosted.org/packages/92/cb/01e0a0551d6934f1158a7f90f690b4a68c1a08ba519ea4ab113e4064e499/optree-0.19.0-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba4925025a47b12237ff8acdcf8b9e972e7f36acafb291373d4de318a4b1b12c", size = 459863, upload-time = "2026-02-23T01:54:57.045Z" }, - { url = "https://files.pythonhosted.org/packages/b2/65/16b9c07e894a51e807404855e717e7e8221ce55f7fec3df46e9dc67c378c/optree-0.19.0-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a8d873ae944fb7d11797bb2ea2666379e78a4608e918d69a4c97fef4779f7da4", size = 459552, upload-time = "2026-02-23T01:54:58.159Z" }, - { url = "https://files.pythonhosted.org/packages/c3/34/3c9e11011c73457dc00e031713df6822eb0690cb849f479796073e070a56/optree-0.19.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6437d23f2708fe0fcdba9d3d75a1b82022caf2c15248059b8bf7e563422fb71", size = 441096, upload-time = "2026-02-23T01:54:59.536Z" }, - { url = "https://files.pythonhosted.org/packages/9c/39/0932e49b76fc3354a9c39c8bb57b04661e83b28fa6c74be09b520d98915b/optree-0.19.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:c2e01d07b2368f25932d5c6071d270a1d4db9e6cb2014eaafeded3d4c73ee406", size = 404747, upload-time = "2026-02-23T01:55:00.591Z" }, - { url = "https://files.pythonhosted.org/packages/ef/d4/11ba9195b65bd77f8955bad5aca8c5fbfb0b273e52c4e7b29b3416c587f0/optree-0.19.0-cp311-cp311-win32.whl", hash = "sha256:846d07372ebc2ca959e9660b28d7c59ae34a02aac2fb73d0f3ec3de79af2fcb0", size = 306775, upload-time = "2026-02-23T01:55:01.659Z" }, - { url = "https://files.pythonhosted.org/packages/d9/13/ee6a65060edde25517151eff8a9e1468e6fd65054fabd14a441161eeafd6/optree-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:29d757b394641703098e1f9a62203c46a5f5cfa260cb8546bd05c8a2cdaf8754", size = 331592, upload-time = "2026-02-23T01:55:03.089Z" }, - { url = "https://files.pythonhosted.org/packages/cf/5e/3a4a66d0ecee599b948d2ef17010fcb9c111c69753a3911e4301005169a8/optree-0.19.0-cp311-cp311-win_arm64.whl", hash = "sha256:fd425b501420b437d5e925708898fae927660fd433836ac282adb20d54561c63", size = 343392, upload-time = "2026-02-23T01:55:04.201Z" }, - { url = "https://files.pythonhosted.org/packages/83/88/a31c2b7ee12f2c7a24a8d57aeecbbcd4c513152212aa1958fff736900033/optree-0.19.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2806e7baafc3c2985b71a5202fe3bde75838c7f09c0df0aa43a2e7ae12e65587", size = 411712, upload-time = "2026-02-23T01:56:31.829Z" }, - { url = "https://files.pythonhosted.org/packages/e7/db/33b61930bf2a879d9b114e63723ccf3965404d4fb5caffad5bee1a5be61c/optree-0.19.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:c39df2d664e3d54faaabfeda3ccfc4a768fc1314578b9ef741055387e13ef3bb", size = 384082, upload-time = "2026-02-23T01:56:32.962Z" }, - { url = "https://files.pythonhosted.org/packages/81/b1/64d04f0169feba3555434013ba2328019c2bde4d5d14600acfdcb91102a9/optree-0.19.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8bdb37b57863f18fad5601af4b94e8bc0ac145040b0ecbbc87f93d27fd6a676e", size = 403543, upload-time = "2026-02-23T01:56:33.983Z" }, - { url = "https://files.pythonhosted.org/packages/39/5c/cc9683a8c9eb54ba48739b7c394503d7df7a22b9f4bd2463ace46bbec593/optree-0.19.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b279f6d5e1cfe681b8bc8678529048081fe5ddaf49333a8bb13f3fb978dfdea", size = 444272, upload-time = "2026-02-23T01:56:35.453Z" }, - { url = "https://files.pythonhosted.org/packages/10/a7/9eb8b63ea378274517233ba0f2f0091a4cf38d92f91c9b1e6e646af31a8b/optree-0.19.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7bcb4e3e0b2b6db57e0882f0ba6b03a07d1489887e7e75d75c42b0e2be9f0019", size = 335393, upload-time = "2026-02-23T01:56:36.659Z" }, + { url = "https://files.pythonhosted.org/packages/d8/eb/389a7dae8b113064f53909707aea9d72372fdc2eb918c48783c443cb3438/optree-0.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09fbc0e5e42b20cab11851dffb7abe2fdf289c45d29e5be2b50b4ea93d069a9f", size = 640773, upload-time = "2025-07-25T11:24:37.25Z" }, + { url = "https://files.pythonhosted.org/packages/2b/bb/2d78b524989cabb5720e85ea366addc8589b4bbd0ce3f5ea58e370e5636a/optree-0.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:90a5864689268eda75d90abded5d474ae0a7ae2608d510626724fb78a1955948", size = 346402, upload-time = "2025-07-25T11:24:38.25Z" }, + { url = "https://files.pythonhosted.org/packages/73/5c/13a2a864b0c0b39c3c193be534a195a3ab2463c7d0443d4a76e749e3ff83/optree-0.17.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3080c564c9760711aa72d1b4d700ce1417f99ad087136f415c4eb8221169e2a3", size = 362797, upload-time = "2025-07-25T11:24:39.509Z" }, + { url = "https://files.pythonhosted.org/packages/da/f5/ff7dcb5a0108ee89c2be09aed2ebd26a7e1333d8122031aa9d9322b24ee6/optree-0.17.0-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:834a8fb358b608240b3a38706a09b43974675624485fad64c8ee641dae2eb57d", size = 419450, upload-time = "2025-07-25T11:24:40.555Z" }, + { url = "https://files.pythonhosted.org/packages/1b/e6/48a97aefd18770b55e5ed456d8183891f325cdb6d90592e5f072ed6951f8/optree-0.17.0-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1a2bd263e6b5621d000d0f94de1f245414fd5dbce365a24b7b89b1ed0ef56cf9", size = 417557, upload-time = "2025-07-25T11:24:42.396Z" }, + { url = "https://files.pythonhosted.org/packages/c4/b1/4e280edab8a86be47ec1f9bd9ed4b685d2e15f0950ae62b613b26d12a1da/optree-0.17.0-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9b37daca4ad89339b1f5320cc61ac600dcf976adbb060769d36d5542d6ebfedf", size = 414174, upload-time = "2025-07-25T11:24:43.51Z" }, + { url = "https://files.pythonhosted.org/packages/db/3b/49a9a1986215dd342525974deeb17c260a83fee8fad147276fd710ac8718/optree-0.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a146a6917f3e28cfdc268ff1770aa696c346482dd3da681c3ff92153d94450ea", size = 402000, upload-time = "2025-07-25T11:24:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/00/8d/13b79d3394b83f4b1c93daac336f0eca5cb1cd5f58e10618f2c2db779cb7/optree-0.17.0-cp311-cp311-win32.whl", hash = "sha256:6b0446803d08f6aaae84f82f03c51527f36dfa15850873fc0183792247bc0071", size = 285777, upload-time = "2025-07-25T11:24:45.976Z" }, + { url = "https://files.pythonhosted.org/packages/90/32/da5191a347e33a78c2804a0cbfaed8eecb758818efda4b4d70bfd9b9b38d/optree-0.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:e39f4f00b2967116badd9617ad6aa9845d8327fe13b6dbf5bc36d8c7b4a5ea03", size = 313761, upload-time = "2025-07-25T11:24:47.047Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ea/7cae17a37a8ef67a33c354fce6f136d5f253d5afa40f68701252b1b2c2a0/optree-0.17.0-cp311-cp311-win_arm64.whl", hash = "sha256:50d4dbcbca3e379cc6b374f9b5a5626ff7ea41df8373e26c3af41d89d8a4b3d5", size = 318242, upload-time = "2025-07-25T11:24:48.708Z" }, + { url = "https://files.pythonhosted.org/packages/ca/40/afec131d9dd7a18d129190d407d97c95994f42b70c3d8ab897092d4de1d9/optree-0.17.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:bd92011cd0f2de40d28a95842819e778c476ab25c12731bfef1d1a0225554f83", size = 353955, upload-time = "2025-07-25T11:26:06.75Z" }, + { url = "https://files.pythonhosted.org/packages/69/c4/94a187ed3ca71194b9da6a276790e1703c7544c8f695ac915214ae8ce934/optree-0.17.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f87f6f39015fc82d7adeee19900d246b89911319726e93cb2dbd4d1a809899bd", size = 363728, upload-time = "2025-07-25T11:26:07.959Z" }, + { url = "https://files.pythonhosted.org/packages/cd/99/23b7a484da8dfb814107b20ef2c93ef27c04f36aeb83bd976964a5b69e06/optree-0.17.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:58b0a83a967d2ef0f343db7182f0ad074eb1166bcaea909ae33909462013f151", size = 404649, upload-time = "2025-07-25T11:26:09.463Z" }, + { url = "https://files.pythonhosted.org/packages/bc/1f/7eca6da47eadb9ff2183bc9169eadde3dda0518e9a0187b99d5926fb2994/optree-0.17.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e1ae8cbbcfaa45c57f5e51c544afa554cefbbb9fe9586c108aaf2aebfadf5899", size = 316368, upload-time = "2025-07-25T11:26:10.572Z" }, ] [[package]] name = "orjson" -version = "3.11.8" +version = "3.11.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/1b/2024d06792d0779f9dbc51531b61c24f76c75b9f4ce05e6f3377a1814cea/orjson-3.11.8.tar.gz", hash = "sha256:96163d9cdc5a202703e9ad1b9ae757d5f0ca62f4fa0cc93d1f27b0e180cc404e", size = 5603832, upload-time = "2026-03-31T16:16:27.878Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/67/41/5aa7fa3b0f4dc6b47dcafc3cea909299c37e40e9972feabc8b6a74e2730d/orjson-3.11.8-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:003646067cc48b7fcab2ae0c562491c9b5d2cbd43f1e5f16d98fd118c5522d34", size = 229229, upload-time = "2026-03-31T16:14:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/0a/d7/57e7f2458e0a2c41694f39fc830030a13053a84f837a5b73423dca1f0938/orjson-3.11.8-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:ed193ce51d77a3830cad399a529cd4ef029968761f43ddc549e1bc62b40d88f8", size = 128871, upload-time = "2026-03-31T16:14:51.888Z" }, - { url = "https://files.pythonhosted.org/packages/53/4a/e0fdb9430983e6c46e0299559275025075568aad5d21dd606faee3703924/orjson-3.11.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30491bc4f862aa15744b9738517454f1e46e56c972a2be87d70d727d5b2a8f8", size = 132104, upload-time = "2026-03-31T16:14:53.142Z" }, - { url = "https://files.pythonhosted.org/packages/08/4a/2025a60ff3f5c8522060cda46612d9b1efa653de66ed2908591d8d82f22d/orjson-3.11.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eda5b8b6be91d3f26efb7dc6e5e68ee805bc5617f65a328587b35255f138bf4", size = 130483, upload-time = "2026-03-31T16:14:54.605Z" }, - { url = "https://files.pythonhosted.org/packages/2d/3c/b9cde05bdc7b2385c66014e0620627da638d3d04e4954416ab48c31196c5/orjson-3.11.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee8db7bfb6fe03581bbab54d7c4124a6dd6a7f4273a38f7267197890f094675f", size = 135481, upload-time = "2026-03-31T16:14:55.901Z" }, - { url = "https://files.pythonhosted.org/packages/ff/f2/a8238e7734de7cb589fed319857a8025d509c89dc52fdcc88f39c6d03d5a/orjson-3.11.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d8b5231de76c528a46b57010bbd83fb51e056aa0220a372fd5065e978406f1c", size = 146819, upload-time = "2026-03-31T16:14:57.548Z" }, - { url = "https://files.pythonhosted.org/packages/db/10/dbf1e2a3cafea673b1b4350e371877b759060d6018a998643b7040e5de48/orjson-3.11.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58a4a208a6fbfdb7a7327b8f201c6014f189f721fd55d047cafc4157af1bc62a", size = 132846, upload-time = "2026-03-31T16:14:58.91Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fc/55e667ec9c85694038fcff00573d221b085d50777368ee3d77f38668bf3c/orjson-3.11.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f8952d6d2505c003e8f0224ff7858d341fa4e33fef82b91c4ff0ef070f2393c", size = 133580, upload-time = "2026-03-31T16:15:00.519Z" }, - { url = "https://files.pythonhosted.org/packages/7e/a6/c08c589a9aad0cb46c4831d17de212a2b6901f9d976814321ff8e69e8785/orjson-3.11.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0022bb50f90da04b009ce32c512dc1885910daa7cb10b7b0cba4505b16db82a8", size = 142042, upload-time = "2026-03-31T16:15:01.906Z" }, - { url = "https://files.pythonhosted.org/packages/5c/cc/2f78ea241d52b717d2efc38878615fe80425bf2beb6e68c984dde257a766/orjson-3.11.8-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ff51f9d657d1afb6f410cb435792ce4e1fe427aab23d2fcd727a2876e21d4cb6", size = 423845, upload-time = "2026-03-31T16:15:03.703Z" }, - { url = "https://files.pythonhosted.org/packages/70/07/c17dcf05dd8045457538428a983bf1f1127928df5bf328cb24d2b7cddacb/orjson-3.11.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6dbe9a97bdb4d8d9d5367b52a7c32549bba70b2739c58ef74a6964a6d05ae054", size = 147729, upload-time = "2026-03-31T16:15:05.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/6c/0fb6e8a24e682e0958d71711ae6f39110e4b9cd8cab1357e2a89cb8e1951/orjson-3.11.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5c370674ebabe16c6ccac33ff80c62bf8a6e59439f5e9d40c1f5ab8fd2215b7", size = 136425, upload-time = "2026-03-31T16:15:07.052Z" }, - { url = "https://files.pythonhosted.org/packages/b2/35/4d3cc3a3d616035beb51b24a09bb872942dc452cf2df0c1d11ab35046d9f/orjson-3.11.8-cp311-cp311-win32.whl", hash = "sha256:0e32f7154299f42ae66f13488963269e5eccb8d588a65bc839ed986919fc9fac", size = 131870, upload-time = "2026-03-31T16:15:08.678Z" }, - { url = "https://files.pythonhosted.org/packages/13/26/9fe70f81d16b702f8c3a775e8731b50ad91d22dacd14c7599b60a0941cd1/orjson-3.11.8-cp311-cp311-win_amd64.whl", hash = "sha256:25e0c672a2e32348d2eb33057b41e754091f2835f87222e4675b796b92264f06", size = 127440, upload-time = "2026-03-31T16:15:09.994Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c6/b038339f4145efd2859c1ca53097a52c0bb9cbdd24f947ebe146da1ad067/orjson-3.11.8-cp311-cp311-win_arm64.whl", hash = "sha256:9185589c1f2a944c17e26c9925dcdbc2df061cc4a145395c57f0c51f9b5dbfcd", size = 127399, upload-time = "2026-03-31T16:15:11.412Z" }, + { url = "https://files.pythonhosted.org/packages/63/1d/1ea6005fffb56715fd48f632611e163d1604e8316a5bad2288bee9a1c9eb/orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39", size = 243498, upload-time = "2025-10-24T15:48:48.101Z" }, + { url = "https://files.pythonhosted.org/packages/37/d7/ffed10c7da677f2a9da307d491b9eb1d0125b0307019c4ad3d665fd31f4f/orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d", size = 128961, upload-time = "2025-10-24T15:48:49.571Z" }, + { url = "https://files.pythonhosted.org/packages/a2/96/3e4d10a18866d1368f73c8c44b7fe37cc8a15c32f2a7620be3877d4c55a3/orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175", size = 130321, upload-time = "2025-10-24T15:48:50.713Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1f/465f66e93f434f968dd74d5b623eb62c657bdba2332f5a8be9f118bb74c7/orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040", size = 129207, upload-time = "2025-10-24T15:48:52.193Z" }, + { url = "https://files.pythonhosted.org/packages/28/43/d1e94837543321c119dff277ae8e348562fe8c0fafbb648ef7cb0c67e521/orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63", size = 136323, upload-time = "2025-10-24T15:48:54.806Z" }, + { url = "https://files.pythonhosted.org/packages/bf/04/93303776c8890e422a5847dd012b4853cdd88206b8bbd3edc292c90102d1/orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9", size = 137440, upload-time = "2025-10-24T15:48:56.326Z" }, + { url = "https://files.pythonhosted.org/packages/1e/ef/75519d039e5ae6b0f34d0336854d55544ba903e21bf56c83adc51cd8bf82/orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a", size = 136680, upload-time = "2025-10-24T15:48:57.476Z" }, + { url = "https://files.pythonhosted.org/packages/b5/18/bf8581eaae0b941b44efe14fee7b7862c3382fbc9a0842132cfc7cf5ecf4/orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be", size = 136160, upload-time = "2025-10-24T15:48:59.631Z" }, + { url = "https://files.pythonhosted.org/packages/c4/35/a6d582766d351f87fc0a22ad740a641b0a8e6fc47515e8614d2e4790ae10/orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7", size = 140318, upload-time = "2025-10-24T15:49:00.834Z" }, + { url = "https://files.pythonhosted.org/packages/76/b3/5a4801803ab2e2e2d703bce1a56540d9f99a9143fbec7bf63d225044fef8/orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549", size = 406330, upload-time = "2025-10-24T15:49:02.327Z" }, + { url = "https://files.pythonhosted.org/packages/80/55/a8f682f64833e3a649f620eafefee175cbfeb9854fc5b710b90c3bca45df/orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905", size = 149580, upload-time = "2025-10-24T15:49:03.517Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e4/c132fa0c67afbb3eb88274fa98df9ac1f631a675e7877037c611805a4413/orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907", size = 139846, upload-time = "2025-10-24T15:49:04.761Z" }, + { url = "https://files.pythonhosted.org/packages/54/06/dc3491489efd651fef99c5908e13951abd1aead1257c67f16135f95ce209/orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c", size = 135781, upload-time = "2025-10-24T15:49:05.969Z" }, + { url = "https://files.pythonhosted.org/packages/79/b7/5e5e8d77bd4ea02a6ac54c42c818afb01dd31961be8a574eb79f1d2cfb1e/orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a", size = 131391, upload-time = "2025-10-24T15:49:07.355Z" }, + { url = "https://files.pythonhosted.org/packages/0f/dc/9484127cc1aa213be398ed735f5f270eedcb0c0977303a6f6ddc46b60204/orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045", size = 126252, upload-time = "2025-10-24T15:49:08.869Z" }, ] [[package]] @@ -2887,11 +2777,11 @@ wheels = [ [[package]] name = "packaging" -version = "26.2" +version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] [[package]] @@ -2946,11 +2836,11 @@ wheels = [ [[package]] name = "parso" -version = "0.8.6" +version = "0.8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621, upload-time = "2026-02-09T15:45:24.425Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894, upload-time = "2026-02-09T15:45:21.391Z" }, + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] [[package]] @@ -2976,28 +2866,28 @@ wheels = [ [[package]] name = "pillow" -version = "12.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, - { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, - { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, - { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, - { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, - { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, - { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, - { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, - { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, - { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, - { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, +version = "12.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/5a/a2f6773b64edb921a756eb0729068acad9fc5208a53f4a349396e9436721/pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc", size = 5289798, upload-time = "2025-10-15T18:21:47.763Z" }, + { url = "https://files.pythonhosted.org/packages/2e/05/069b1f8a2e4b5a37493da6c5868531c3f77b85e716ad7a590ef87d58730d/pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257", size = 4650589, upload-time = "2025-10-15T18:21:49.515Z" }, + { url = "https://files.pythonhosted.org/packages/61/e3/2c820d6e9a36432503ead175ae294f96861b07600a7156154a086ba7111a/pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642", size = 6230472, upload-time = "2025-10-15T18:21:51.052Z" }, + { url = "https://files.pythonhosted.org/packages/4f/89/63427f51c64209c5e23d4d52071c8d0f21024d3a8a487737caaf614a5795/pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3", size = 8033887, upload-time = "2025-10-15T18:21:52.604Z" }, + { url = "https://files.pythonhosted.org/packages/f6/1b/c9711318d4901093c15840f268ad649459cd81984c9ec9887756cca049a5/pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c", size = 6343964, upload-time = "2025-10-15T18:21:54.619Z" }, + { url = "https://files.pythonhosted.org/packages/41/1e/db9470f2d030b4995083044cd8738cdd1bf773106819f6d8ba12597d5352/pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227", size = 7034756, upload-time = "2025-10-15T18:21:56.151Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b0/6177a8bdd5ee4ed87cba2de5a3cc1db55ffbbec6176784ce5bb75aa96798/pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b", size = 6458075, upload-time = "2025-10-15T18:21:57.759Z" }, + { url = "https://files.pythonhosted.org/packages/bc/5e/61537aa6fa977922c6a03253a0e727e6e4a72381a80d63ad8eec350684f2/pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e", size = 7125955, upload-time = "2025-10-15T18:21:59.372Z" }, + { url = "https://files.pythonhosted.org/packages/1f/3d/d5033539344ee3cbd9a4d69e12e63ca3a44a739eb2d4c8da350a3d38edd7/pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739", size = 6298440, upload-time = "2025-10-15T18:22:00.982Z" }, + { url = "https://files.pythonhosted.org/packages/4d/42/aaca386de5cc8bd8a0254516957c1f265e3521c91515b16e286c662854c4/pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e", size = 6999256, upload-time = "2025-10-15T18:22:02.617Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f1/9197c9c2d5708b785f631a6dfbfa8eb3fb9672837cb92ae9af812c13b4ed/pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d", size = 2436025, upload-time = "2025-10-15T18:22:04.598Z" }, + { url = "https://files.pythonhosted.org/packages/1d/b3/582327e6c9f86d037b63beebe981425d6811104cb443e8193824ef1a2f27/pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8", size = 5215068, upload-time = "2025-10-15T18:23:59.594Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d6/67748211d119f3b6540baf90f92fae73ae51d5217b171b0e8b5f7e5d558f/pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a", size = 4614994, upload-time = "2025-10-15T18:24:01.669Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e1/f8281e5d844c41872b273b9f2c34a4bf64ca08905668c8ae730eedc7c9fa/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197", size = 5246639, upload-time = "2025-10-15T18:24:03.403Z" }, + { url = "https://files.pythonhosted.org/packages/94/5a/0d8ab8ffe8a102ff5df60d0de5af309015163bf710c7bb3e8311dd3b3ad0/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c", size = 6986839, upload-time = "2025-10-15T18:24:05.344Z" }, + { url = "https://files.pythonhosted.org/packages/20/2e/3434380e8110b76cd9eb00a363c484b050f949b4bbe84ba770bb8508a02c/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e", size = 5313505, upload-time = "2025-10-15T18:24:07.137Z" }, + { url = "https://files.pythonhosted.org/packages/57/ca/5a9d38900d9d74785141d6580950fe705de68af735ff6e727cb911b64740/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76", size = 5963654, upload-time = "2025-10-15T18:24:09.579Z" }, + { url = "https://files.pythonhosted.org/packages/95/7e/f896623c3c635a90537ac093c6a618ebe1a90d87206e42309cb5d98a1b9e/pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5", size = 6997850, upload-time = "2025-10-15T18:24:11.495Z" }, ] [[package]] @@ -3011,11 +2901,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.9.6" +version = "4.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, ] [[package]] @@ -3084,44 +2974,42 @@ wheels = [ [[package]] name = "proto-plus" -version = "1.27.2" +version = "1.26.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/81/0d/94dfe80193e79d55258345901acd2917523d56e8381bc4dee7fd38e3868a/proto_plus-1.27.2.tar.gz", hash = "sha256:b2adde53adadf75737c44d3dcb0104fde65250dfc83ad59168b4aa3e574b6a24", size = 57204, upload-time = "2026-03-26T22:18:57.174Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142, upload-time = "2025-03-10T15:54:38.843Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/f3/1fba73eeffafc998a25d59703b63f8be4fe8a5cb12eaff7386a0ba0f7125/proto_plus-1.27.2-py3-none-any.whl", hash = "sha256:6432f75893d3b9e70b9c412f1d2f03f65b11fb164b793d14ae2ca01821d22718", size = 50450, upload-time = "2026-03-26T22:13:42.927Z" }, + { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163, upload-time = "2025-03-10T15:54:37.335Z" }, ] [[package]] name = "protobuf" -version = "4.25.9" +version = "4.25.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d9/8e/d08c41a8c004e1d437ef467e7c4f9c3295cd784eba48ed5d1d01f94b1dad/protobuf-4.25.9.tar.gz", hash = "sha256:b0dc7e7c68de8b1ce831dacb12fb407e838edbb8b6cc0dc3a2a6b4cbf6de9cff", size = 381040, upload-time = "2026-03-25T23:09:36.423Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/01/34c8d2b6354906d728703cb9d546a0e534de479e25f1b581e4094c4a85cc/protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd", size = 380920, upload-time = "2025-05-28T14:22:25.153Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/e9/59435bd04bdd46cb38c42a336b22f9843e8e586ff83c35a5423f8b14704e/protobuf-4.25.9-cp310-abi3-win32.whl", hash = "sha256:bde396f568b0b46fc8fbfe9f02facf25b6755b2578a3b8ac61e74b9d69499e03", size = 392879, upload-time = "2026-03-25T23:09:21.32Z" }, - { url = "https://files.pythonhosted.org/packages/f3/16/42a5c7f1001783d2b5bfcecde10127f09010f78982c86ae409122ce3ece6/protobuf-4.25.9-cp310-abi3-win_amd64.whl", hash = "sha256:3683c05154252206f7cb2d371626514b3708199d9bcf683b503dabf3a2e38e06", size = 413900, upload-time = "2026-03-25T23:09:23.589Z" }, - { url = "https://files.pythonhosted.org/packages/56/5b/0074a0a9eb01f3d1c4648ca5e81b22090c811b210b61df9018ac6d6c5cda/protobuf-4.25.9-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:9560813560e6ee72c11ca8873878bdb7ee003c96a57ebb013245fe84e2540904", size = 394826, upload-time = "2026-03-25T23:09:25.194Z" }, - { url = "https://files.pythonhosted.org/packages/54/aa/b2dba856f64c36b2a06c67be1472de98cca07a2322d0f0cbf03279a40e5b/protobuf-4.25.9-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:999146ef02e7fa6a692477badd1528bcd7268df211852a3df2d834ba2b480791", size = 294191, upload-time = "2026-03-25T23:09:26.613Z" }, - { url = "https://files.pythonhosted.org/packages/a8/5c/53f18822017b8bda6bd8bb4e02048e911fdc79a3dafdc83ab994fe922a84/protobuf-4.25.9-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:438c636de8fb706a0de94a12a268ef1ae8f5ba5ae655a7671fcda5968ba3c9be", size = 295178, upload-time = "2026-03-25T23:09:27.839Z" }, - { url = "https://files.pythonhosted.org/packages/16/28/d5065b212685875d3924bcdb3201cbf467cb4d58a18aa19a8dfd99ea80a9/protobuf-4.25.9-py3-none-any.whl", hash = "sha256:d49b615e7c935194ac161f0965699ac84df6112c378e05ec53da65d2e4cbb6d4", size = 156822, upload-time = "2026-03-25T23:09:34.957Z" }, + { url = "https://files.pythonhosted.org/packages/45/ff/05f34305fe6b85bbfbecbc559d423a5985605cad5eda4f47eae9e9c9c5c5/protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0", size = 392745, upload-time = "2025-05-28T14:22:10.524Z" }, + { url = "https://files.pythonhosted.org/packages/08/35/8b8a8405c564caf4ba835b1fdf554da869954712b26d8f2a98c0e434469b/protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9", size = 413736, upload-time = "2025-05-28T14:22:13.156Z" }, + { url = "https://files.pythonhosted.org/packages/28/d7/ab27049a035b258dab43445eb6ec84a26277b16105b277cbe0a7698bdc6c/protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f", size = 394537, upload-time = "2025-05-28T14:22:14.768Z" }, + { url = "https://files.pythonhosted.org/packages/bd/6d/a4a198b61808dd3d1ee187082ccc21499bc949d639feb948961b48be9a7e/protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7", size = 294005, upload-time = "2025-05-28T14:22:16.052Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c6/c9deaa6e789b6fc41b88ccbdfe7a42d2b82663248b715f55aa77fbc00724/protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0", size = 294924, upload-time = "2025-05-28T14:22:17.105Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c1/6aece0ab5209981a70cd186f164c133fdba2f51e124ff92b73de7fd24d78/protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59", size = 156757, upload-time = "2025-05-28T14:22:24.135Z" }, ] [[package]] name = "psutil" -version = "7.2.2" +version = "7.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/ec/7b8e6b9b1d22708138630ef34c53ab2b61032c04f16adfdbb96791c8c70c/psutil-7.1.2.tar.gz", hash = "sha256:aa225cdde1335ff9684708ee8c72650f6598d5ed2114b9a7c5802030b1785018", size = 487424, upload-time = "2025-10-25T10:46:34.931Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, - { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, - { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, - { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, - { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, - { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, - { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, - { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, + { url = "https://files.pythonhosted.org/packages/ae/89/b9f8d47ddbc52d7301fc868e8224e5f44ed3c7f55e6d0f54ecaf5dd9ff5e/psutil-7.1.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9ba5c19f2d46203ee8c152c7b01df6eec87d883cfd8ee1af2ef2727f6b0f814", size = 237244, upload-time = "2025-10-25T10:47:07.086Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7a/8628c2f6b240680a67d73d8742bb9ff39b1820a693740e43096d5dcb01e5/psutil-7.1.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a486030d2fe81bec023f703d3d155f4823a10a47c36784c84f1cc7f8d39bedb", size = 238101, upload-time = "2025-10-25T10:47:09.523Z" }, + { url = "https://files.pythonhosted.org/packages/30/28/5e27f4d5a0e347f8e3cc16cd7d35533dbce086c95807f1f0e9cd77e26c10/psutil-7.1.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3efd8fc791492e7808a51cb2b94889db7578bfaea22df931424f874468e389e3", size = 258675, upload-time = "2025-10-25T10:47:11.082Z" }, + { url = "https://files.pythonhosted.org/packages/e5/5c/79cf60c9acf36d087f0db0f82066fca4a780e97e5b3a2e4c38209c03d170/psutil-7.1.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2aeb9b64f481b8eabfc633bd39e0016d4d8bbcd590d984af764d80bf0851b8a", size = 260203, upload-time = "2025-10-25T10:47:13.226Z" }, + { url = "https://files.pythonhosted.org/packages/f7/03/0a464404c51685dcb9329fdd660b1721e076ccd7b3d97dee066bcc9ffb15/psutil-7.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:8e17852114c4e7996fe9da4745c2bdef001ebbf2f260dec406290e66628bdb91", size = 246714, upload-time = "2025-10-25T10:47:15.093Z" }, + { url = "https://files.pythonhosted.org/packages/6a/32/97ca2090f2f1b45b01b6aa7ae161cfe50671de097311975ca6eea3e7aabc/psutil-7.1.2-cp37-abi3-win_arm64.whl", hash = "sha256:3e988455e61c240cc879cb62a008c2699231bf3e3d061d7fce4234463fd2abb4", size = 243742, upload-time = "2025-10-25T10:47:17.302Z" }, ] [[package]] @@ -3169,11 +3057,11 @@ wheels = [ [[package]] name = "pyasn1" -version = "0.6.3" +version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, ] [[package]] @@ -3199,16 +3087,16 @@ wheels = [ [[package]] name = "pycparser" -version = "3.0" +version = "2.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, ] [[package]] name = "pydantic" -version = "2.13.3" +version = "2.12.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -3216,47 +3104,46 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/1e/4f0a3233767010308f2fd6bd0814597e3f63f1dc98304a9112b8759df4ff/pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74", size = 819383, upload-time = "2025-10-17T15:04:21.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/0a/fd7d723f8f8153418fb40cf9c940e82004fce7e987026b08a68a36dd3fe7/pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927", size = 471981, upload-time = "2026-04-20T14:46:41.402Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/83661fa77dcefa195ad5f8cd9af3d1a7450fd57cc883ad04d65446ac2029/pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf", size = 462431, upload-time = "2025-10-17T15:04:19.346Z" }, ] [[package]] name = "pydantic-core" -version = "2.46.3" +version = "2.41.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a2/1ba90a83e85a3f94c796b184f3efde9c72f2830dcda493eea8d59ba78e6d/pydantic_core-2.46.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ab124d49d0459b2373ecf54118a45c28a1e6d4192a533fbc915e70f556feb8e5", size = 2106740, upload-time = "2026-04-20T14:41:20.932Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f6/99ae893c89a0b9d3daec9f95487aa676709aa83f67643b3f0abaf4ab628a/pydantic_core-2.46.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cca67d52a5c7a16aed2b3999e719c4bcf644074eac304a5d3d62dd70ae7d4b2c", size = 1948293, upload-time = "2026-04-20T14:43:42.115Z" }, - { url = "https://files.pythonhosted.org/packages/3e/b8/2e8e636dc9e3f16c2e16bf0849e24be82c5ee82c603c65fc0326666328fc/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c024e08c0ba23e6fd68c771a521e9d6a792f2ebb0fa734296b36394dc30390e", size = 1973222, upload-time = "2026-04-20T14:41:57.841Z" }, - { url = "https://files.pythonhosted.org/packages/34/36/0e730beec4d83c5306f417afbd82ff237d9a21e83c5edf675f31ed84c1fe/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6645ce7eec4928e29a1e3b3d5c946621d105d3e79f0c9cddf07c2a9770949287", size = 2053852, upload-time = "2026-04-20T14:40:43.077Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f0/3071131f47e39136a17814576e0fada9168569f7f8c0e6ac4d1ede6a4958/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a712c7118e6c5ea96562f7b488435172abb94a3c53c22c9efc1412264a45cbbe", size = 2221134, upload-time = "2026-04-20T14:43:03.349Z" }, - { url = "https://files.pythonhosted.org/packages/2f/a9/a2dc023eec5aa4b02a467874bad32e2446957d2adcab14e107eab502e978/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a868ef3ff206343579021c40faf3b1edc64b1cc508ff243a28b0a514ccb050", size = 2279785, upload-time = "2026-04-20T14:41:19.285Z" }, - { url = "https://files.pythonhosted.org/packages/0a/44/93f489d16fb63fbd41c670441536541f6e8cfa1e5a69f40bc9c5d30d8c90/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7e8c32db809aa0f6ea1d6869ebc8518a65d5150fdfad8bcae6a49ae32a22e2", size = 2089404, upload-time = "2026-04-20T14:43:10.108Z" }, - { url = "https://files.pythonhosted.org/packages/2a/78/8692e3aa72b2d004f7a5d937f1dfdc8552ba26caf0bec75f342c40f00dec/pydantic_core-2.46.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3481bd1341dc85779ee506bc8e1196a277ace359d89d28588a9468c3ecbe63fa", size = 2114898, upload-time = "2026-04-20T14:44:51.475Z" }, - { url = "https://files.pythonhosted.org/packages/6a/62/e83133f2e7832532060175cebf1f13748f4c7e7e7165cdd1f611f174494b/pydantic_core-2.46.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8690eba565c6d68ffd3a8655525cbdd5246510b44a637ee2c6c03a7ebfe64d3c", size = 2157856, upload-time = "2026-04-20T14:43:46.64Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ec/6a500e3ad7718ee50583fae79c8651f5d37e3abce1fa9ae177ae65842c53/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4de88889d7e88d50d40ee5b39d5dac0bcaef9ba91f7e536ac064e6b2834ecccf", size = 2180168, upload-time = "2026-04-20T14:42:00.302Z" }, - { url = "https://files.pythonhosted.org/packages/d8/53/8267811054b1aa7fc1dc7ded93812372ef79a839f5e23558136a6afbfde1/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:e480080975c1ef7f780b8f99ed72337e7cc5efea2e518a20a692e8e7b278eb8b", size = 2322885, upload-time = "2026-04-20T14:41:05.253Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c1/1c0acdb3aa0856ddc4ecc55214578f896f2de16f400cf51627eb3c26c1c4/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de3a5c376f8cd94da9a1b8fd3dd1c16c7a7b216ed31dc8ce9fd7a22bf13b836e", size = 2360328, upload-time = "2026-04-20T14:41:43.991Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d0/ef39cd0f4a926814f360e71c1adeab48ad214d9727e4deb48eedfb5bce1a/pydantic_core-2.46.3-cp311-cp311-win32.whl", hash = "sha256:fc331a5314ffddd5385b9ee9d0d2fee0b13c27e0e02dad71b1ae5d6561f51eeb", size = 1979464, upload-time = "2026-04-20T14:43:12.215Z" }, - { url = "https://files.pythonhosted.org/packages/18/9c/f41951b0d858e343f1cf09398b2a7b3014013799744f2c4a8ad6a3eec4f2/pydantic_core-2.46.3-cp311-cp311-win_amd64.whl", hash = "sha256:b5b9c6cf08a8a5e502698f5e153056d12c34b8fb30317e0c5fd06f45162a6346", size = 2070837, upload-time = "2026-04-20T14:41:47.707Z" }, - { url = "https://files.pythonhosted.org/packages/9f/1e/264a17cd582f6ed50950d4d03dd5fefd84e570e238afe1cb3e25cf238769/pydantic_core-2.46.3-cp311-cp311-win_arm64.whl", hash = "sha256:5dfd51cf457482f04ec49491811a2b8fd5b843b64b11eecd2d7a1ee596ea78a6", size = 2053647, upload-time = "2026-04-20T14:42:27.535Z" }, - { url = "https://files.pythonhosted.org/packages/66/7f/03dbad45cd3aa9083fbc93c210ae8b005af67e4136a14186950a747c6874/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:9715525891ed524a0a1eb6d053c74d4d4ad5017677fb00af0b7c2644a31bae46", size = 2105683, upload-time = "2026-04-20T14:42:19.779Z" }, - { url = "https://files.pythonhosted.org/packages/26/22/4dc186ac8ea6b257e9855031f51b62a9637beac4d68ac06bee02f046f836/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:9d2f400712a99a013aff420ef1eb9be077f8189a36c1e3ef87660b4e1088a874", size = 1940052, upload-time = "2026-04-20T14:43:59.274Z" }, - { url = "https://files.pythonhosted.org/packages/0d/ca/d376391a5aff1f2e8188960d7873543608130a870961c2b6b5236627c116/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd2aab0e2e9dc2daf36bd2686c982535d5e7b1d930a1344a7bb6e82baab42a76", size = 1988172, upload-time = "2026-04-20T14:41:17.469Z" }, - { url = "https://files.pythonhosted.org/packages/0e/6b/523b9f85c23788755d6ab949329de692a2e3a584bc6beb67fef5e035aa9d/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9d76736da5f362fabfeea6a69b13b7f2be405c6d6966f06b2f6bfff7e64531", size = 2128596, upload-time = "2026-04-20T14:40:41.707Z" }, - { url = "https://files.pythonhosted.org/packages/1f/da/99d40830684f81dec901cac521b5b91c095394cc1084b9433393cde1c2df/pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:13afdd885f3d71280cf286b13b310ee0f7ccfefd1dbbb661514a474b726e2f25", size = 2107973, upload-time = "2026-04-20T14:42:06.175Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/87024121818d75bbb2a98ddbaf638e40e7a18b5e0f5492c9ca4b1b316107/pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f91c0aff3e3ee0928edd1232c57f643a7a003e6edf1860bc3afcdc749cb513f3", size = 1947191, upload-time = "2026-04-20T14:43:14.319Z" }, - { url = "https://files.pythonhosted.org/packages/60/62/0c1acfe10945b83a6a59d19fbaa92f48825381509e5701b855c08f13db76/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6529d1d128321a58d30afcc97b49e98836542f68dd41b33c2e972bb9e5290536", size = 2123791, upload-time = "2026-04-20T14:43:22.766Z" }, - { url = "https://files.pythonhosted.org/packages/75/3e/3b2393b4c8f44285561dc30b00cf307a56a2eff7c483a824db3b8221ca51/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:975c267cff4f7e7272eacbe50f6cc03ca9a3da4c4fbd66fffd89c94c1e311aa1", size = 2153197, upload-time = "2026-04-20T14:44:27.932Z" }, - { url = "https://files.pythonhosted.org/packages/ba/75/5af02fb35505051eee727c061f2881c555ab4f8ddb2d42da715a42c9731b/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2b8e4f2bbdf71415c544b4b1138b8060db7b6611bc927e8064c769f64bed651c", size = 2181073, upload-time = "2026-04-20T14:43:20.729Z" }, - { url = "https://files.pythonhosted.org/packages/10/92/7e0e1bd9ca3c68305db037560ca2876f89b2647deb2f8b6319005de37505/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e61ea8e9fff9606d09178f577ff8ccdd7206ff73d6552bcec18e1033c4254b85", size = 2315886, upload-time = "2026-04-20T14:44:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/b8/d8/101655f27eaf3e44558ead736b2795d12500598beed4683f279396fa186e/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b504bda01bafc69b6d3c7a0c7f039dcf60f47fab70e06fe23f57b5c75bdc82b8", size = 2360528, upload-time = "2026-04-20T14:40:47.431Z" }, - { url = "https://files.pythonhosted.org/packages/07/0f/1c34a74c8d07136f0d729ffe5e1fdab04fbdaa7684f61a92f92511a84a15/pydantic_core-2.46.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b00b76f7142fc60c762ce579bd29c8fa44aaa56592dd3c54fab3928d0d4ca6ff", size = 2184144, upload-time = "2026-04-20T14:42:57Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/df/18/d0944e8eaaa3efd0a91b0f1fc537d3be55ad35091b6a87638211ba691964/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5", size = 457557, upload-time = "2025-10-14T10:23:47.909Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/4c/f6cbfa1e8efacd00b846764e8484fe173d25b8dab881e277a619177f3384/pydantic_core-2.41.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:28ff11666443a1a8cf2a044d6a545ebffa8382b5f7973f22c36109205e65dc80", size = 2109062, upload-time = "2025-10-14T10:20:04.486Z" }, + { url = "https://files.pythonhosted.org/packages/21/f8/40b72d3868896bfcd410e1bd7e516e762d326201c48e5b4a06446f6cf9e8/pydantic_core-2.41.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:61760c3925d4633290292bad462e0f737b840508b4f722247d8729684f6539ae", size = 1916301, upload-time = "2025-10-14T10:20:06.857Z" }, + { url = "https://files.pythonhosted.org/packages/94/4d/d203dce8bee7faeca791671c88519969d98d3b4e8f225da5b96dad226fc8/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae547b7315d055b0de2ec3965643b0ab82ad0106a7ffd29615ee9f266a02827", size = 1968728, upload-time = "2025-10-14T10:20:08.353Z" }, + { url = "https://files.pythonhosted.org/packages/65/f5/6a66187775df87c24d526985b3a5d78d861580ca466fbd9d4d0e792fcf6c/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef9ee5471edd58d1fcce1c80ffc8783a650e3e3a193fe90d52e43bb4d87bff1f", size = 2050238, upload-time = "2025-10-14T10:20:09.766Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b9/78336345de97298cf53236b2f271912ce11f32c1e59de25a374ce12f9cce/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15dd504af121caaf2c95cb90c0ebf71603c53de98305621b94da0f967e572def", size = 2249424, upload-time = "2025-10-14T10:20:11.732Z" }, + { url = "https://files.pythonhosted.org/packages/99/bb/a4584888b70ee594c3d374a71af5075a68654d6c780369df269118af7402/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a926768ea49a8af4d36abd6a8968b8790f7f76dd7cbd5a4c180db2b4ac9a3a2", size = 2366047, upload-time = "2025-10-14T10:20:13.647Z" }, + { url = "https://files.pythonhosted.org/packages/5f/8d/17fc5de9d6418e4d2ae8c675f905cdafdc59d3bf3bf9c946b7ab796a992a/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916b9b7d134bff5440098a4deb80e4cb623e68974a87883299de9124126c2a8", size = 2071163, upload-time = "2025-10-14T10:20:15.307Z" }, + { url = "https://files.pythonhosted.org/packages/54/e7/03d2c5c0b8ed37a4617430db68ec5e7dbba66358b629cd69e11b4d564367/pydantic_core-2.41.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cf90535979089df02e6f17ffd076f07237efa55b7343d98760bde8743c4b265", size = 2190585, upload-time = "2025-10-14T10:20:17.3Z" }, + { url = "https://files.pythonhosted.org/packages/be/fc/15d1c9fe5ad9266a5897d9b932b7f53d7e5cfc800573917a2c5d6eea56ec/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7533c76fa647fade2d7ec75ac5cc079ab3f34879626dae5689b27790a6cf5a5c", size = 2150109, upload-time = "2025-10-14T10:20:19.143Z" }, + { url = "https://files.pythonhosted.org/packages/26/ef/e735dd008808226c83ba56972566138665b71477ad580fa5a21f0851df48/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:37e516bca9264cbf29612539801ca3cd5d1be465f940417b002905e6ed79d38a", size = 2315078, upload-time = "2025-10-14T10:20:20.742Z" }, + { url = "https://files.pythonhosted.org/packages/90/00/806efdcf35ff2ac0f938362350cd9827b8afb116cc814b6b75cf23738c7c/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c19cb355224037c83642429b8ce261ae108e1c5fbf5c028bac63c77b0f8646e", size = 2318737, upload-time = "2025-10-14T10:20:22.306Z" }, + { url = "https://files.pythonhosted.org/packages/41/7e/6ac90673fe6cb36621a2283552897838c020db343fa86e513d3f563b196f/pydantic_core-2.41.4-cp311-cp311-win32.whl", hash = "sha256:09c2a60e55b357284b5f31f5ab275ba9f7f70b7525e18a132ec1f9160b4f1f03", size = 1974160, upload-time = "2025-10-14T10:20:23.817Z" }, + { url = "https://files.pythonhosted.org/packages/e0/9d/7c5e24ee585c1f8b6356e1d11d40ab807ffde44d2db3b7dfd6d20b09720e/pydantic_core-2.41.4-cp311-cp311-win_amd64.whl", hash = "sha256:711156b6afb5cb1cb7c14a2cc2c4a8b4c717b69046f13c6b332d8a0a8f41ca3e", size = 2021883, upload-time = "2025-10-14T10:20:25.48Z" }, + { url = "https://files.pythonhosted.org/packages/33/90/5c172357460fc28b2871eb4a0fb3843b136b429c6fa827e4b588877bf115/pydantic_core-2.41.4-cp311-cp311-win_arm64.whl", hash = "sha256:6cb9cf7e761f4f8a8589a45e49ed3c0d92d1d696a45a6feaee8c904b26efc2db", size = 1968026, upload-time = "2025-10-14T10:20:27.039Z" }, + { url = "https://files.pythonhosted.org/packages/b0/12/5ba58daa7f453454464f92b3ca7b9d7c657d8641c48e370c3ebc9a82dd78/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:a1b2cfec3879afb742a7b0bcfa53e4f22ba96571c9e54d6a3afe1052d17d843b", size = 2122139, upload-time = "2025-10-14T10:22:47.288Z" }, + { url = "https://files.pythonhosted.org/packages/21/fb/6860126a77725c3108baecd10fd3d75fec25191d6381b6eb2ac660228eac/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:d175600d975b7c244af6eb9c9041f10059f20b8bbffec9e33fdd5ee3f67cdc42", size = 1936674, upload-time = "2025-10-14T10:22:49.555Z" }, + { url = "https://files.pythonhosted.org/packages/de/be/57dcaa3ed595d81f8757e2b44a38240ac5d37628bce25fb20d02c7018776/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f184d657fa4947ae5ec9c47bd7e917730fa1cbb78195037e32dcbab50aca5ee", size = 1956398, upload-time = "2025-10-14T10:22:52.19Z" }, + { url = "https://files.pythonhosted.org/packages/2f/1d/679a344fadb9695f1a6a294d739fbd21d71fa023286daeea8c0ed49e7c2b/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed810568aeffed3edc78910af32af911c835cc39ebbfacd1f0ab5dd53028e5c", size = 2138674, upload-time = "2025-10-14T10:22:54.499Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7d/138e902ed6399b866f7cfe4435d22445e16fff888a1c00560d9dc79a780f/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:491535d45cd7ad7e4a2af4a5169b0d07bebf1adfd164b0368da8aa41e19907a5", size = 2104721, upload-time = "2025-10-14T10:23:26.906Z" }, + { url = "https://files.pythonhosted.org/packages/47/13/0525623cf94627f7b53b4c2034c81edc8491cbfc7c28d5447fa318791479/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:54d86c0cada6aba4ec4c047d0e348cbad7063b87ae0f005d9f8c9ad04d4a92a2", size = 1931608, upload-time = "2025-10-14T10:23:29.306Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f9/744bc98137d6ef0a233f808bfc9b18cf94624bf30836a18d3b05d08bf418/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca1124aced216b2500dc2609eade086d718e8249cb9696660ab447d50a758bd", size = 2132986, upload-time = "2025-10-14T10:23:32.057Z" }, + { url = "https://files.pythonhosted.org/packages/17/c8/629e88920171173f6049386cc71f893dff03209a9ef32b4d2f7e7c264bcf/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c9024169becccf0cb470ada03ee578d7348c119a0d42af3dcf9eda96e3a247c", size = 2187516, upload-time = "2025-10-14T10:23:34.871Z" }, + { url = "https://files.pythonhosted.org/packages/2e/0f/4f2734688d98488782218ca61bcc118329bf5de05bb7fe3adc7dd79b0b86/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:26895a4268ae5a2849269f4991cdc97236e4b9c010e51137becf25182daac405", size = 2146146, upload-time = "2025-10-14T10:23:37.342Z" }, + { url = "https://files.pythonhosted.org/packages/ed/f2/ab385dbd94a052c62224b99cf99002eee99dbec40e10006c78575aead256/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:ca4df25762cf71308c446e33c9b1fdca2923a3f13de616e2a949f38bf21ff5a8", size = 2311296, upload-time = "2025-10-14T10:23:40.145Z" }, + { url = "https://files.pythonhosted.org/packages/fc/8e/e4f12afe1beeb9823bba5375f8f258df0cc61b056b0195fb1cf9f62a1a58/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5a28fcedd762349519276c36634e71853b4541079cab4acaaac60c4421827308", size = 2315386, upload-time = "2025-10-14T10:23:42.624Z" }, + { url = "https://files.pythonhosted.org/packages/48/f7/925f65d930802e3ea2eb4d5afa4cb8730c8dc0d2cb89a59dc4ed2fcb2d74/pydantic_core-2.41.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c173ddcd86afd2535e2b695217e82191580663a1d1928239f877f5a1649ef39f", size = 2147775, upload-time = "2025-10-14T10:23:45.406Z" }, ] [[package]] @@ -3297,32 +3184,32 @@ sdist = { url = "https://files.pythonhosted.org/packages/c3/7f/256f1954343fc4464 [[package]] name = "pyg-lib" -version = "0.6.0+pt28cpu" +version = "0.5.0+pt28cpu" source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } resolution-markers = [ "sys_platform != 'darwin'", ] wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.6.0%2Bpt28cpu-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.6.0%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.5.0%2Bpt28cpu-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/pyg_lib-0.5.0%2Bpt28cpu-cp311-cp311-win_amd64.whl" }, ] [[package]] name = "pyg-lib" -version = "0.6.0+pt28cu128" +version = "0.5.0+pt28cu128" source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cu128.html" } wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.6.0%2Bpt28cu128-cp311-cp311-manylinux_2_28_x86_64.whl" }, - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.6.0%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.5.0%2Bpt28cu128-cp311-cp311-linux_x86_64.whl" }, + { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/pyg_lib-0.5.0%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, ] [[package]] name = "pygments" -version = "2.20.0" +version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] [[package]] @@ -3333,41 +3220,41 @@ sdist = { url = "https://files.pythonhosted.org/packages/48/ef/c72abcfa2c6accd03 [[package]] name = "pyjwt" -version = "2.12.1" +version = "2.10.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" }, + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, ] [[package]] name = "pymongo" -version = "4.17.0" +version = "4.15.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dnspython" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ca/64/50be6fbac9c79fe2e4c17401a467da2d8764d82833d83cec325afe5cab32/pymongo-4.17.0.tar.gz", hash = "sha256:70ffa08ba641468cc068cf46c06b34f01a8ce3489f6411309fcb5ceabe6b2fc0", size = 2523370, upload-time = "2026-04-20T16:39:53.524Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/7b/a709c85dc716eb85b69f71a4bb375cf1e72758a7e872103f27551243319c/pymongo-4.15.3.tar.gz", hash = "sha256:7a981271347623b5319932796690c2d301668ac3a1965974ac9f5c3b8a22cea5", size = 2470801, upload-time = "2025-10-07T21:57:50.384Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/e2/336d86f221cf1b56b2ed9330d4a3b98f9f38f0b37829ae9a9184617d5419/pymongo-4.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4141e6c6a339789b2974efa00ecd9409101672d77a0e3ee2cc3839eedf8ec4df", size = 874668, upload-time = "2026-04-20T16:37:41.39Z" }, - { url = "https://files.pythonhosted.org/packages/34/8e/75d3c6c935d187ab59c61e9c15d9aab3f274b563eaf1706e8cae5f508dec/pymongo-4.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e68c76b84e0c132d9dbf9307f12ff8185702328187a87b9aca8c941303873433", size = 875294, upload-time = "2026-04-20T16:37:43.432Z" }, - { url = "https://files.pythonhosted.org/packages/5f/ec/62e855744489dbcd54fd778aae4d80fa4c4819e8fb228ca0cf6f21a03997/pymongo-4.17.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ba2195d4f386f839a52a23ea1cfd60ffaaba78a3d7841db51b7e433001139918", size = 1496233, upload-time = "2026-04-20T16:37:45.518Z" }, - { url = "https://files.pythonhosted.org/packages/82/e8/93e4e5e5ce8fdf8929dabeefe24aafa5ce046028eed0dfa8eeb936e72c49/pymongo-4.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8446ff4bfcb6ec2a2e50998c860986a1e992136f998b7f53e7a717fb8aa5a0b9", size = 1522927, upload-time = "2026-04-20T16:37:47.492Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ca/425dc1d21e0f17bdea0072fc463f662f7fa06d2852af52975c9eced3c07c/pymongo-4.17.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2a0d5ac205728c86e0a02192f1aa5f865b0d7d51f8df6101c01a69a7fc620d72", size = 1583468, upload-time = "2026-04-20T16:37:49.221Z" }, - { url = "https://files.pythonhosted.org/packages/b3/9d/f08b07eeffda1a43c1759f0fa625e88ae12360996eb56d42aad832fa7dff/pymongo-4.17.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:485c8a8eaa4c739f00a331fc73757898ee7c092c214a79e63866ff76aaf282ff", size = 1572787, upload-time = "2026-04-20T16:37:51.061Z" }, - { url = "https://files.pythonhosted.org/packages/e9/c2/6855a07aafa7b894929af23675b6fb9634800ce43122b76a62f6eeb8da2a/pymongo-4.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b2dfcc795f5b9fedbe179a11fdf6051581479d196582a3fe819a92a00e9b9969", size = 1526184, upload-time = "2026-04-20T16:37:53.358Z" }, - { url = "https://files.pythonhosted.org/packages/4e/05/c952bac7db71c1942ea3559fcd308b49754cc5004b455935fb4000d1f37b/pymongo-4.17.0-cp311-cp311-win32.whl", hash = "sha256:c2292144505fb12156b981bd440f3dc994a883da06ac726c0c8692ccdbc1c510", size = 852621, upload-time = "2026-04-20T16:37:55.28Z" }, - { url = "https://files.pythonhosted.org/packages/11/c0/c04da9f4c0c6252404598f4e394b862a58a9e866822a70ae261c8a018fdf/pymongo-4.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:2e190827834fce70ecdf9d46796c6dbc0ce08ea87dc2ff5bc6f3f5579b605cb9", size = 867852, upload-time = "2026-04-20T16:37:57.233Z" }, - { url = "https://files.pythonhosted.org/packages/1d/b2/c7b4870fbeef471e947d3e014676f5910d02e0197074d692ebcf24ec049a/pymongo-4.17.0-cp311-cp311-win_arm64.whl", hash = "sha256:a8f9c40a09bb7d4b9fc8b1da65ecf6efa79bda5cb2756f39d9b6940fac1d19ae", size = 855019, upload-time = "2026-04-20T16:37:58.983Z" }, + { url = "https://files.pythonhosted.org/packages/73/04/3dbc426c5868961d8308f19750243f8472f587f5f8a5029ce6953ba74b82/pymongo-4.15.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a13d8f7141294404ce46dfbabb2f2d17e9b1192456651ae831fa351f86fbeb", size = 865889, upload-time = "2025-10-07T21:56:14.165Z" }, + { url = "https://files.pythonhosted.org/packages/8c/39/7f7652f53dd0eb0c4c3420a175183da757e9c53f9a2bf3ebc589758a1b9e/pymongo-4.15.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:17d13458baf4a6a9f2e787d95adf8ec50d412accb9926a044bd1c41029c323b2", size = 866230, upload-time = "2025-10-07T21:56:15.587Z" }, + { url = "https://files.pythonhosted.org/packages/6a/0b/84e119e6bab7b19cf4fa1ebb9b4c29bf6c0e76521ed8221b44e3f94a3a37/pymongo-4.15.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fe4bcb8acfb288e238190397d4a699aeb4adb70e8545a6f4e44f99d4e8096ab1", size = 1429788, upload-time = "2025-10-07T21:56:17.362Z" }, + { url = "https://files.pythonhosted.org/packages/30/39/9905fcb99903de6ac8483114d1c85efe56bc5df735857bdfcc372cf8a3ec/pymongo-4.15.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d09d895c7f08bcbed4d2e96a00e52e9e545ae5a37b32d2dc10099b205a21fc6d", size = 1456758, upload-time = "2025-10-07T21:56:18.841Z" }, + { url = "https://files.pythonhosted.org/packages/08/58/3c3ac32b8d6ebb654083d53f58e4621cd4c7f306b3b85acef667b80acf08/pymongo-4.15.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:21c0a95a4db72562fd0805e2f76496bf432ba2e27a5651f4b9c670466260c258", size = 1514666, upload-time = "2025-10-07T21:56:20.488Z" }, + { url = "https://files.pythonhosted.org/packages/19/e2/52f41de224218dc787b7e1187a1ca1a51946dcb979ee553ec917745ccd8d/pymongo-4.15.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:89e45d7fa987f4e246cdf43ff001e3f911f73eb19ba9dabc2a6d80df5c97883b", size = 1500703, upload-time = "2025-10-07T21:56:21.874Z" }, + { url = "https://files.pythonhosted.org/packages/34/0d/a5271073339ba6fc8a5f4e3a62baaa5dd8bf35246c37b512317e2a22848e/pymongo-4.15.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1246a82fa6dd73ac2c63aa7e463752d5d1ca91e0c7a23396b78f21273befd3a7", size = 1452013, upload-time = "2025-10-07T21:56:23.526Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3b/f39b721ca0db9f0820e12eeffec84eb87b7502abb13a685226c5434f9618/pymongo-4.15.3-cp311-cp311-win32.whl", hash = "sha256:9483521c03f6017336f54445652ead3145154e8d3ea06418e52cea57fee43292", size = 844461, upload-time = "2025-10-07T21:56:24.867Z" }, + { url = "https://files.pythonhosted.org/packages/12/72/e58b9df862edbf238a1d71fa32749a6eaf30a3f60289602681351c29093a/pymongo-4.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:c57dad9f289d72af1d7c47a444c4d9fa401f951cedbbcc54c7dd0c2107d6d786", size = 859200, upload-time = "2025-10-07T21:56:26.393Z" }, + { url = "https://files.pythonhosted.org/packages/81/8f/64c15df5e87de759412c3b962950561202c9b39e5cc604061e056043e163/pymongo-4.15.3-cp311-cp311-win_arm64.whl", hash = "sha256:2fd3b99520f2bb013960ac29dece1b43f2f1b6d94351ca33ba1b1211ecf79a09", size = 848372, upload-time = "2025-10-07T21:56:27.994Z" }, ] [[package]] name = "pyparsing" -version = "3.3.2" +version = "3.2.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, + { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, ] [[package]] @@ -3375,8 +3262,8 @@ name = "pyre-extensions" version = "0.0.32" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, - { name = "typing-inspect" }, + { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-inspect", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/53/5bc2532536e921c48366ad1047c1344ccef6afa5e84053f0f6e20a453767/pyre_extensions-0.0.32.tar.gz", hash = "sha256:5396715f14ea56c4d5fd0a88c57ca7e44faa468f905909edd7de4ad90ed85e55", size = 10852, upload-time = "2024-11-22T19:26:44.152Z" } wheels = [ @@ -3395,44 +3282,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] -[[package]] -name = "python-discovery" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "filelock" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", size = 58872, upload-time = "2026-04-07T17:28:49.249Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", size = 31894, upload-time = "2026-04-07T17:28:48.09Z" }, -] - [[package]] name = "python-dotenv" -version = "1.2.2" +version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] [[package]] name = "pytz" -version = "2026.1.post1" +version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] [[package]] name = "pyvers" -version = "0.2.2" +version = "0.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/32/99/23c73a1298b1c642d8ebdd78e1db4daf1e474152e6839df4f5c93357a3db/pyvers-0.2.2.tar.gz", hash = "sha256:205026bcd0b4c09198cb3a32f243fd179ef012882ce16d93dcb755320acd56f7", size = 12104, upload-time = "2026-01-23T14:12:07.619Z" } +dependencies = [ + { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, +] wheels = [ - { url = "https://files.pythonhosted.org/packages/36/bf/ea840f706b7824dd57220484465995309c8c217995ddb7ce4b262240e912/pyvers-0.2.2-py3-none-any.whl", hash = "sha256:c4696408a0b15fbaa90df33d3bc579cf23a74a73541858f5470216f12f51f3b1", size = 11569, upload-time = "2026-01-23T14:12:06.246Z" }, + { url = "https://files.pythonhosted.org/packages/7f/39/c5432f541e6ea1d616dfd6ef42ce02792f7eb42dd44f5ed4439dbe17a58b/pyvers-0.1.0-py3-none-any.whl", hash = "sha256:065249805ae537ddf9a2d1a8dffc6d0a12474a347d2eaa2f35ebdae92c0c8199", size = 10092, upload-time = "2025-06-08T23:46:46.219Z" }, ] [[package]] @@ -3527,31 +3403,29 @@ wheels = [ [[package]] name = "regex" -version = "2026.4.4" +version = "2025.10.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/3a246dbf05666918bd3664d9d787f84a9108f6f43cc953a077e4a7dfdb7e/regex-2026.4.4.tar.gz", hash = "sha256:e08270659717f6973523ce3afbafa53515c4dc5dcad637dc215b6fd50f689423", size = 416000, upload-time = "2026-04-03T20:56:28.155Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/c8/1d2160d36b11fbe0a61acb7c3c81ab032d9ec8ad888ac9e0a61b85ab99dd/regex-2025.10.23.tar.gz", hash = "sha256:8cbaf8ceb88f96ae2356d01b9adf5e6306fa42fa6f7eab6b97794e37c959ac26", size = 401266, upload-time = "2025-10-21T15:58:20.23Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/7a/617356cbecdb452812a5d42f720d6d5096b360d4a4c1073af700ea140ad2/regex-2026.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4c36a85b00fadb85db9d9e90144af0a980e1a3d2ef9cd0f8a5bef88054657c6", size = 489415, upload-time = "2026-04-03T20:53:11.645Z" }, - { url = "https://files.pythonhosted.org/packages/20/e6/bf057227144d02e3ba758b66649e87531d744dda5f3254f48660f18ae9d8/regex-2026.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dcb5453ecf9cd58b562967badd1edbf092b0588a3af9e32ee3d05c985077ce87", size = 291205, upload-time = "2026-04-03T20:53:13.289Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3b/637181b787dd1a820ba1c712cee2b4144cd84a32dc776ca067b12b2d70c8/regex-2026.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6aa809ed4dc3706cc38594d67e641601bd2f36d5555b2780ff074edfcb136cf8", size = 289225, upload-time = "2026-04-03T20:53:16.002Z" }, - { url = "https://files.pythonhosted.org/packages/05/21/bac05d806ed02cd4b39d9c8e5b5f9a2998c94c3a351b7792e80671fa5315/regex-2026.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33424f5188a7db12958246a54f59a435b6cb62c5cf9c8d71f7cc49475a5fdada", size = 792434, upload-time = "2026-04-03T20:53:17.414Z" }, - { url = "https://files.pythonhosted.org/packages/d9/17/c65d1d8ae90b772d5758eb4014e1e011bb2db353fc4455432e6cc9100df7/regex-2026.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d346fccdde28abba117cc9edc696b9518c3307fbfcb689e549d9b5979018c6d", size = 861730, upload-time = "2026-04-03T20:53:18.903Z" }, - { url = "https://files.pythonhosted.org/packages/ad/64/933321aa082a2c6ee2785f22776143ba89840189c20d3b6b1d12b6aae16b/regex-2026.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:415a994b536440f5011aa77e50a4274d15da3245e876e5c7f19da349caaedd87", size = 906495, upload-time = "2026-04-03T20:53:20.561Z" }, - { url = "https://files.pythonhosted.org/packages/01/ea/4c8d306e9c36ac22417336b1e02e7b358152c34dc379673f2d331143725f/regex-2026.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21e5eb86179b4c67b5759d452ea7c48eb135cd93308e7a260aa489ed2eb423a4", size = 799810, upload-time = "2026-04-03T20:53:22.961Z" }, - { url = "https://files.pythonhosted.org/packages/29/ce/7605048f00e1379eba89d610c7d644d8f695dc9b26d3b6ecfa3132b872ff/regex-2026.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:312ec9dd1ae7d96abd8c5a36a552b2139931914407d26fba723f9e53c8186f86", size = 774242, upload-time = "2026-04-03T20:53:25.015Z" }, - { url = "https://files.pythonhosted.org/packages/e9/77/283e0d5023fde22cd9e86190d6d9beb21590a452b195ffe00274de470691/regex-2026.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0d2b28aa1354c7cd7f71b7658c4326f7facac106edd7f40eda984424229fd59", size = 781257, upload-time = "2026-04-03T20:53:26.918Z" }, - { url = "https://files.pythonhosted.org/packages/8b/fb/7f3b772be101373c8626ed34c5d727dcbb8abd42a7b1219bc25fd9a3cc04/regex-2026.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:349d7310eddff40429a099c08d995c6d4a4bfaf3ff40bd3b5e5cb5a5a3c7d453", size = 854490, upload-time = "2026-04-03T20:53:29.065Z" }, - { url = "https://files.pythonhosted.org/packages/85/30/56547b80f34f4dd2986e1cdd63b1712932f63b6c4ce2f79c50a6cd79d1c2/regex-2026.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e7ab63e9fe45a9ec3417509e18116b367e89c9ceb6219222a3396fa30b147f80", size = 763544, upload-time = "2026-04-03T20:53:30.917Z" }, - { url = "https://files.pythonhosted.org/packages/ac/2f/ce060fdfea8eff34a8997603532e44cdb7d1f35e3bc253612a8707a90538/regex-2026.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fe896e07a5a2462308297e515c0054e9ec2dd18dfdc9427b19900b37dfe6f40b", size = 844442, upload-time = "2026-04-03T20:53:32.463Z" }, - { url = "https://files.pythonhosted.org/packages/e5/44/810cb113096a1dacbe82789fbfab2823f79d19b7f1271acecb7009ba9b88/regex-2026.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb59c65069498dbae3c0ef07bbe224e1eaa079825a437fb47a479f0af11f774f", size = 789162, upload-time = "2026-04-03T20:53:34.039Z" }, - { url = "https://files.pythonhosted.org/packages/20/96/9647dd7f2ecf6d9ce1fb04dfdb66910d094e10d8fe53e9c15096d8aa0bd2/regex-2026.4.4-cp311-cp311-win32.whl", hash = "sha256:2a5d273181b560ef8397c8825f2b9d57013de744da9e8257b8467e5da8599351", size = 266227, upload-time = "2026-04-03T20:53:35.601Z" }, - { url = "https://files.pythonhosted.org/packages/33/80/74e13262460530c3097ff343a17de9a34d040a5dc4de9cf3a8241faab51c/regex-2026.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:9542ccc1e689e752594309444081582f7be2fdb2df75acafea8a075108566735", size = 278399, upload-time = "2026-04-03T20:53:37.021Z" }, - { url = "https://files.pythonhosted.org/packages/1c/3c/39f19f47f19dcefa3403f09d13562ca1c0fd07ab54db2bc03148f3f6b46a/regex-2026.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:b5f9fb784824a042be3455b53d0b112655686fdb7a91f88f095f3fee1e2a2a54", size = 270473, upload-time = "2026-04-03T20:53:38.633Z" }, + { url = "https://files.pythonhosted.org/packages/82/e5/74b7cd5cd76b4171f9793042045bb1726f7856dd56e582fc3e058a7a8a5e/regex-2025.10.23-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6c531155bf9179345e85032052a1e5fe1a696a6abf9cea54b97e8baefff970fd", size = 487960, upload-time = "2025-10-21T15:54:53.253Z" }, + { url = "https://files.pythonhosted.org/packages/b9/08/854fa4b3b20471d1df1c71e831b6a1aa480281e37791e52a2df9641ec5c6/regex-2025.10.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:912e9df4e89d383681268d38ad8f5780d7cccd94ba0e9aa09ca7ab7ab4f8e7eb", size = 290425, upload-time = "2025-10-21T15:54:55.21Z" }, + { url = "https://files.pythonhosted.org/packages/ab/d3/6272b1dd3ca1271661e168762b234ad3e00dbdf4ef0c7b9b72d2d159efa7/regex-2025.10.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f375c61bfc3138b13e762fe0ae76e3bdca92497816936534a0177201666f44f", size = 288278, upload-time = "2025-10-21T15:54:56.862Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/c7b365dd9d9bc0a36e018cb96f2ffb60d2ba8deb589a712b437f67de2920/regex-2025.10.23-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e248cc9446081119128ed002a3801f8031e0c219b5d3c64d3cc627da29ac0a33", size = 793289, upload-time = "2025-10-21T15:54:58.352Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fb/b8fbe9aa16cf0c21f45ec5a6c74b4cecbf1a1c0deb7089d4a6f83a9c1caa/regex-2025.10.23-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b52bf9282fdf401e4f4e721f0f61fc4b159b1307244517789702407dd74e38ca", size = 860321, upload-time = "2025-10-21T15:54:59.813Z" }, + { url = "https://files.pythonhosted.org/packages/b0/81/bf41405c772324926a9bd8a640dedaa42da0e929241834dfce0733070437/regex-2025.10.23-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c084889ab2c59765a0d5ac602fd1c3c244f9b3fcc9a65fdc7ba6b74c5287490", size = 907011, upload-time = "2025-10-21T15:55:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/a4/fb/5ad6a8b92d3f88f3797b51bb4ef47499acc2d0b53d2fbe4487a892f37a73/regex-2025.10.23-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d80e8eb79009bdb0936658c44ca06e2fbbca67792013e3818eea3f5f228971c2", size = 800312, upload-time = "2025-10-21T15:55:04.15Z" }, + { url = "https://files.pythonhosted.org/packages/42/48/b4efba0168a2b57f944205d823f8e8a3a1ae6211a34508f014ec2c712f4f/regex-2025.10.23-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6f259118ba87b814a8ec475380aee5f5ae97a75852a3507cf31d055b01b5b40", size = 782839, upload-time = "2025-10-21T15:55:05.641Z" }, + { url = "https://files.pythonhosted.org/packages/13/2a/c9efb4c6c535b0559c1fa8e431e0574d229707c9ca718600366fcfef6801/regex-2025.10.23-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9b8c72a242683dcc72d37595c4f1278dfd7642b769e46700a8df11eab19dfd82", size = 854270, upload-time = "2025-10-21T15:55:07.27Z" }, + { url = "https://files.pythonhosted.org/packages/34/2d/68eecc1bdaee020e8ba549502291c9450d90d8590d0552247c9b543ebf7b/regex-2025.10.23-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a8d7b7a0a3df9952f9965342159e0c1f05384c0f056a47ce8b61034f8cecbe83", size = 845771, upload-time = "2025-10-21T15:55:09.477Z" }, + { url = "https://files.pythonhosted.org/packages/a5/cd/a1ae499cf9b87afb47a67316bbf1037a7c681ffe447c510ed98c0aa2c01c/regex-2025.10.23-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:413bfea20a484c524858125e92b9ce6ffdd0a4b97d4ff96b5859aa119b0f1bdd", size = 788778, upload-time = "2025-10-21T15:55:11.396Z" }, + { url = "https://files.pythonhosted.org/packages/38/f9/70765e63f5ea7d43b2b6cd4ee9d3323f16267e530fb2a420d92d991cf0fc/regex-2025.10.23-cp311-cp311-win32.whl", hash = "sha256:f76deef1f1019a17dad98f408b8f7afc4bd007cbe835ae77b737e8c7f19ae575", size = 265666, upload-time = "2025-10-21T15:55:13.306Z" }, + { url = "https://files.pythonhosted.org/packages/9c/1a/18e9476ee1b63aaec3844d8e1cb21842dc19272c7e86d879bfc0dcc60db3/regex-2025.10.23-cp311-cp311-win_amd64.whl", hash = "sha256:59bba9f7125536f23fdab5deeea08da0c287a64c1d3acc1c7e99515809824de8", size = 277600, upload-time = "2025-10-21T15:55:15.087Z" }, + { url = "https://files.pythonhosted.org/packages/1d/1b/c019167b1f7a8ec77251457e3ff0339ed74ca8bce1ea13138dc98309c923/regex-2025.10.23-cp311-cp311-win_arm64.whl", hash = "sha256:b103a752b6f1632ca420225718d6ed83f6a6ced3016dd0a4ab9a6825312de566", size = 269974, upload-time = "2025-10-21T15:55:16.841Z" }, ] [[package]] name = "requests" -version = "2.33.1" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -3559,9 +3433,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -3591,50 +3465,50 @@ wheels = [ [[package]] name = "rich" -version = "15.0.0" +version = "14.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, ] [[package]] name = "rpds-py" -version = "0.30.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, - { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, - { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, - { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, - { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, - { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, - { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, - { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, - { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, - { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, - { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, - { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, - { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, - { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, - { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, - { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, - { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, - { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, - { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, - { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, - { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, - { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, - { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, +version = "0.28.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/dc/95f074d43452b3ef5d06276696ece4b3b5d696e7c9ad7173c54b1390cd70/rpds_py-0.28.0.tar.gz", hash = "sha256:abd4df20485a0983e2ca334a216249b6186d6e3c1627e106651943dbdb791aea", size = 27419, upload-time = "2025-10-22T22:24:29.327Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/34/058d0db5471c6be7bef82487ad5021ff8d1d1d27794be8730aad938649cf/rpds_py-0.28.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:03065002fd2e287725d95fbc69688e0c6daf6c6314ba38bdbaa3895418e09296", size = 362344, upload-time = "2025-10-22T22:21:39.713Z" }, + { url = "https://files.pythonhosted.org/packages/5d/67/9503f0ec8c055a0782880f300c50a2b8e5e72eb1f94dfc2053da527444dd/rpds_py-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28ea02215f262b6d078daec0b45344c89e161eab9526b0d898221d96fdda5f27", size = 348440, upload-time = "2025-10-22T22:21:41.056Z" }, + { url = "https://files.pythonhosted.org/packages/68/2e/94223ee9b32332a41d75b6f94b37b4ce3e93878a556fc5f152cbd856a81f/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25dbade8fbf30bcc551cb352376c0ad64b067e4fc56f90e22ba70c3ce205988c", size = 379068, upload-time = "2025-10-22T22:21:42.593Z" }, + { url = "https://files.pythonhosted.org/packages/b4/25/54fd48f9f680cfc44e6a7f39a5fadf1d4a4a1fd0848076af4a43e79f998c/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c03002f54cc855860bfdc3442928ffdca9081e73b5b382ed0b9e8efe6e5e205", size = 390518, upload-time = "2025-10-22T22:21:43.998Z" }, + { url = "https://files.pythonhosted.org/packages/1b/85/ac258c9c27f2ccb1bd5d0697e53a82ebcf8088e3186d5d2bf8498ee7ed44/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9699fa7990368b22032baf2b2dce1f634388e4ffc03dfefaaac79f4695edc95", size = 525319, upload-time = "2025-10-22T22:21:45.645Z" }, + { url = "https://files.pythonhosted.org/packages/40/cb/c6734774789566d46775f193964b76627cd5f42ecf246d257ce84d1912ed/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b06fe1a75e05e0713f06ea0c89ecb6452210fd60e2f1b6ddc1067b990e08d9", size = 404896, upload-time = "2025-10-22T22:21:47.544Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/14e37ce83202c632c89b0691185dca9532288ff9d390eacae3d2ff771bae/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9f83e7b326a3f9ec3ef84cda98fb0a74c7159f33e692032233046e7fd15da2", size = 382862, upload-time = "2025-10-22T22:21:49.176Z" }, + { url = "https://files.pythonhosted.org/packages/6a/83/f3642483ca971a54d60caa4449f9d6d4dbb56a53e0072d0deff51b38af74/rpds_py-0.28.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:0d3259ea9ad8743a75a43eb7819324cdab393263c91be86e2d1901ee65c314e0", size = 398848, upload-time = "2025-10-22T22:21:51.024Z" }, + { url = "https://files.pythonhosted.org/packages/44/09/2d9c8b2f88e399b4cfe86efdf2935feaf0394e4f14ab30c6c5945d60af7d/rpds_py-0.28.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a7548b345f66f6695943b4ef6afe33ccd3f1b638bd9afd0f730dd255c249c9e", size = 412030, upload-time = "2025-10-22T22:21:52.665Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f5/e1cec473d4bde6df1fd3738be8e82d64dd0600868e76e92dfeaebbc2d18f/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9a40040aa388b037eb39416710fbcce9443498d2eaab0b9b45ae988b53f5c67", size = 559700, upload-time = "2025-10-22T22:21:54.123Z" }, + { url = "https://files.pythonhosted.org/packages/8d/be/73bb241c1649edbf14e98e9e78899c2c5e52bbe47cb64811f44d2cc11808/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f60c7ea34e78c199acd0d3cda37a99be2c861dd2b8cf67399784f70c9f8e57d", size = 584581, upload-time = "2025-10-22T22:21:56.102Z" }, + { url = "https://files.pythonhosted.org/packages/9c/9c/ffc6e9218cd1eb5c2c7dbd276c87cd10e8c2232c456b554169eb363381df/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1571ae4292649100d743b26d5f9c63503bb1fedf538a8f29a98dce2d5ba6b4e6", size = 549981, upload-time = "2025-10-22T22:21:58.253Z" }, + { url = "https://files.pythonhosted.org/packages/5f/50/da8b6d33803a94df0149345ee33e5d91ed4d25fc6517de6a25587eae4133/rpds_py-0.28.0-cp311-cp311-win32.whl", hash = "sha256:5cfa9af45e7c1140af7321fa0bef25b386ee9faa8928c80dc3a5360971a29e8c", size = 214729, upload-time = "2025-10-22T22:21:59.625Z" }, + { url = "https://files.pythonhosted.org/packages/12/fd/b0f48c4c320ee24c8c20df8b44acffb7353991ddf688af01eef5f93d7018/rpds_py-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd8d86b5d29d1b74100982424ba53e56033dc47720a6de9ba0259cf81d7cecaa", size = 223977, upload-time = "2025-10-22T22:22:01.092Z" }, + { url = "https://files.pythonhosted.org/packages/b4/21/c8e77a2ac66e2ec4e21f18a04b4e9a0417ecf8e61b5eaeaa9360a91713b4/rpds_py-0.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e27d3a5709cc2b3e013bf93679a849213c79ae0573f9b894b284b55e729e120", size = 217326, upload-time = "2025-10-22T22:22:02.944Z" }, + { url = "https://files.pythonhosted.org/packages/ae/bc/b43f2ea505f28119bd551ae75f70be0c803d2dbcd37c1b3734909e40620b/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f5e7101145427087e493b9c9b959da68d357c28c562792300dd21a095118ed16", size = 363913, upload-time = "2025-10-22T22:24:07.129Z" }, + { url = "https://files.pythonhosted.org/packages/28/f2/db318195d324c89a2c57dc5195058cbadd71b20d220685c5bd1da79ee7fe/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:31eb671150b9c62409a888850aaa8e6533635704fe2b78335f9aaf7ff81eec4d", size = 350452, upload-time = "2025-10-22T22:24:08.754Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f2/1391c819b8573a4898cedd6b6c5ec5bc370ce59e5d6bdcebe3c9c1db4588/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b55c1f64482f7d8bd39942f376bfdf2f6aec637ee8c805b5041e14eeb771db", size = 380957, upload-time = "2025-10-22T22:24:10.826Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5c/e5de68ee7eb7248fce93269833d1b329a196d736aefb1a7481d1e99d1222/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24743a7b372e9a76171f6b69c01aedf927e8ac3e16c474d9fe20d552a8cb45c7", size = 391919, upload-time = "2025-10-22T22:24:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/fb/4f/2376336112cbfeb122fd435d608ad8d5041b3aed176f85a3cb32c262eb80/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:389c29045ee8bbb1627ea190b4976a310a295559eaf9f1464a1a6f2bf84dde78", size = 528541, upload-time = "2025-10-22T22:24:14.197Z" }, + { url = "https://files.pythonhosted.org/packages/68/53/5ae232e795853dd20da7225c5dd13a09c0a905b1a655e92bdf8d78a99fd9/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23690b5827e643150cf7b49569679ec13fe9a610a15949ed48b85eb7f98f34ec", size = 405629, upload-time = "2025-10-22T22:24:16.001Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2d/351a3b852b683ca9b6b8b38ed9efb2347596973849ba6c3a0e99877c10aa/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f0c9266c26580e7243ad0d72fc3e01d6b33866cfab5084a6da7576bcf1c4f72", size = 384123, upload-time = "2025-10-22T22:24:17.585Z" }, + { url = "https://files.pythonhosted.org/packages/e0/15/870804daa00202728cc91cb8e2385fa9f1f4eb49857c49cfce89e304eae6/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4c6c4db5d73d179746951486df97fd25e92396be07fc29ee8ff9a8f5afbdfb27", size = 400923, upload-time = "2025-10-22T22:24:19.512Z" }, + { url = "https://files.pythonhosted.org/packages/53/25/3706b83c125fa2a0bccceac951de3f76631f6bd0ee4d02a0ed780712ef1b/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3b695a8fa799dd2cfdb4804b37096c5f6dba1ac7f48a7fbf6d0485bcd060316", size = 413767, upload-time = "2025-10-22T22:24:21.316Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f9/ce43dbe62767432273ed2584cef71fef8411bddfb64125d4c19128015018/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6aa1bfce3f83baf00d9c5fcdbba93a3ab79958b4c7d7d1f55e7fe68c20e63912", size = 561530, upload-time = "2025-10-22T22:24:22.958Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/ffe77999ed8f81e30713dd38fd9ecaa161f28ec48bb80fa1cd9118399c27/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b0f9dceb221792b3ee6acb5438eb1f02b0cb2c247796a72b016dcc92c6de829", size = 585453, upload-time = "2025-10-22T22:24:24.779Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d2/4a73b18821fd4669762c855fd1f4e80ceb66fb72d71162d14da58444a763/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5d0145edba8abd3db0ab22b5300c99dc152f5c9021fab861be0f0544dc3cbc5f", size = 552199, upload-time = "2025-10-22T22:24:26.54Z" }, ] [[package]] @@ -3689,7 +3563,7 @@ wheels = [ [[package]] name = "scikit-learn" -version = "1.8.0" +version = "1.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "joblib" }, @@ -3697,44 +3571,62 @@ dependencies = [ { name = "scipy" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/92/53ea2181da8ac6bf27170191028aee7251f8f841f8d3edbfdcaf2008fde9/scikit_learn-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:146b4d36f800c013d267b29168813f7a03a43ecd2895d04861f1240b564421da", size = 8595835, upload-time = "2025-12-10T07:07:39.385Z" }, - { url = "https://files.pythonhosted.org/packages/01/18/d154dc1638803adf987910cdd07097d9c526663a55666a97c124d09fb96a/scikit_learn-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f984ca4b14914e6b4094c5d52a32ea16b49832c03bd17a110f004db3c223e8e1", size = 8080381, upload-time = "2025-12-10T07:07:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/8a/44/226142fcb7b7101e64fdee5f49dbe6288d4c7af8abf593237b70fca080a4/scikit_learn-1.8.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e30adb87f0cc81c7690a84f7932dd66be5bac57cfe16b91cb9151683a4a2d3b", size = 8799632, upload-time = "2025-12-10T07:07:43.899Z" }, - { url = "https://files.pythonhosted.org/packages/36/4d/4a67f30778a45d542bbea5db2dbfa1e9e100bf9ba64aefe34215ba9f11f6/scikit_learn-1.8.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ada8121bcb4dac28d930febc791a69f7cb1673c8495e5eee274190b73a4559c1", size = 9103788, upload-time = "2025-12-10T07:07:45.982Z" }, - { url = "https://files.pythonhosted.org/packages/89/3c/45c352094cfa60050bcbb967b1faf246b22e93cb459f2f907b600f2ceda5/scikit_learn-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:c57b1b610bd1f40ba43970e11ce62821c2e6569e4d74023db19c6b26f246cb3b", size = 8081706, upload-time = "2025-12-10T07:07:48.111Z" }, - { url = "https://files.pythonhosted.org/packages/3d/46/5416595bb395757f754feb20c3d776553a386b661658fb21b7c814e89efe/scikit_learn-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:2838551e011a64e3053ad7618dda9310175f7515f1742fa2d756f7c874c05961", size = 7688451, upload-time = "2025-12-10T07:07:49.873Z" }, + { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967, upload-time = "2025-09-09T08:20:32.421Z" }, + { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645, upload-time = "2025-09-09T08:20:34.436Z" }, + { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424, upload-time = "2025-09-09T08:20:36.776Z" }, + { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234, upload-time = "2025-09-09T08:20:38.957Z" }, + { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244, upload-time = "2025-09-09T08:20:41.166Z" }, ] [[package]] name = "scipy" -version = "1.17.1" +version = "1.16.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, - { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, - { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, - { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, - { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, - { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, - { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, - { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, - { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, + { url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881, upload-time = "2025-10-28T17:31:47.104Z" }, + { url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012, upload-time = "2025-10-28T17:31:53.411Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935, upload-time = "2025-10-28T17:31:57.361Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466, upload-time = "2025-10-28T17:32:01.875Z" }, + { url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618, upload-time = "2025-10-28T17:32:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798, upload-time = "2025-10-28T17:32:12.665Z" }, + { url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154, upload-time = "2025-10-28T17:32:17.961Z" }, + { url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540, upload-time = "2025-10-28T17:32:23.907Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107, upload-time = "2025-10-28T17:32:29.921Z" }, + { url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272, upload-time = "2025-10-28T17:32:34.577Z" }, ] [[package]] name = "setuptools" -version = "82.0.1" +version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + +[[package]] +name = "shapely" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/bc/0989043118a27cccb4e906a46b7565ce36ca7b57f5a18b78f4f1b0f72d9d/shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9", size = 315489, upload-time = "2025-09-24T13:51:41.432Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8d/1ff672dea9ec6a7b5d422eb6d095ed886e2e523733329f75fdcb14ee1149/shapely-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91121757b0a36c9aac3427a651a7e6567110a4a67c97edf04f8d55d4765f6618", size = 1820038, upload-time = "2025-09-24T13:50:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/4f/ce/28fab8c772ce5db23a0d86bf0adaee0c4c79d5ad1db766055fa3dab442e2/shapely-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:16a9c722ba774cf50b5d4541242b4cce05aafd44a015290c82ba8a16931ff63d", size = 1626039, upload-time = "2025-09-24T13:50:16.881Z" }, + { url = "https://files.pythonhosted.org/packages/70/8b/868b7e3f4982f5006e9395c1e12343c66a8155c0374fdc07c0e6a1ab547d/shapely-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cc4f7397459b12c0b196c9efe1f9d7e92463cbba142632b4cc6d8bbbbd3e2b09", size = 3001519, upload-time = "2025-09-24T13:50:18.606Z" }, + { url = "https://files.pythonhosted.org/packages/13/02/58b0b8d9c17c93ab6340edd8b7308c0c5a5b81f94ce65705819b7416dba5/shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:136ab87b17e733e22f0961504d05e77e7be8c9b5a8184f685b4a91a84efe3c26", size = 3110842, upload-time = "2025-09-24T13:50:21.77Z" }, + { url = "https://files.pythonhosted.org/packages/af/61/8e389c97994d5f331dcffb25e2fa761aeedfb52b3ad9bcdd7b8671f4810a/shapely-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:16c5d0fc45d3aa0a69074979f4f1928ca2734fb2e0dde8af9611e134e46774e7", size = 4021316, upload-time = "2025-09-24T13:50:23.626Z" }, + { url = "https://files.pythonhosted.org/packages/d3/d4/9b2a9fe6039f9e42ccf2cb3e84f219fd8364b0c3b8e7bbc857b5fbe9c14c/shapely-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ddc759f72b5b2b0f54a7e7cde44acef680a55019eb52ac63a7af2cf17cb9cd2", size = 4178586, upload-time = "2025-09-24T13:50:25.443Z" }, + { url = "https://files.pythonhosted.org/packages/16/f6/9840f6963ed4decf76b08fd6d7fed14f8779fb7a62cb45c5617fa8ac6eab/shapely-2.1.2-cp311-cp311-win32.whl", hash = "sha256:2fa78b49485391224755a856ed3b3bd91c8455f6121fee0db0e71cefb07d0ef6", size = 1543961, upload-time = "2025-09-24T13:50:26.968Z" }, + { url = "https://files.pythonhosted.org/packages/38/1e/3f8ea46353c2a33c1669eb7327f9665103aa3a8dfe7f2e4ef714c210b2c2/shapely-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:c64d5c97b2f47e3cd9b712eaced3b061f2b71234b3fc263e0fcf7d889c6559dc", size = 1722856, upload-time = "2025-09-24T13:50:28.497Z" }, ] [[package]] @@ -3766,11 +3658,11 @@ wheels = [ [[package]] name = "soupsieve" -version = "2.8.3" +version = "2.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, + { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, ] [[package]] @@ -3960,31 +3852,32 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.49" +version = "2.0.44" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830, upload-time = "2025-10-10T14:39:12.935Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/b5/e3617cc67420f8f403efebd7b043128f94775e57e5b84e7255203390ceae/sqlalchemy-2.0.49-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5070135e1b7409c4161133aa525419b0062088ed77c92b1da95366ec5cbebbe", size = 2159126, upload-time = "2026-04-03T16:50:13.242Z" }, - { url = "https://files.pythonhosted.org/packages/20/9b/91ca80403b17cd389622a642699e5f6564096b698e7cdcbcbb6409898bc4/sqlalchemy-2.0.49-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ac7a3e245fd0310fd31495eb61af772e637bdf7d88ee81e7f10a3f271bff014", size = 3315509, upload-time = "2026-04-03T16:54:49.332Z" }, - { url = "https://files.pythonhosted.org/packages/b1/61/0722511d98c54de95acb327824cb759e8653789af2b1944ab1cc69d32565/sqlalchemy-2.0.49-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d4e5a0ceba319942fa6b585cf82539288a61e314ef006c1209f734551ab9536", size = 3315014, upload-time = "2026-04-03T16:56:56.376Z" }, - { url = "https://files.pythonhosted.org/packages/46/55/d514a653ffeb4cebf4b54c47bec32ee28ad89d39fafba16eeed1d81dccd5/sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ddcb27fb39171de36e207600116ac9dfd4ae46f86c82a9bf3934043e80ebb88", size = 3267388, upload-time = "2026-04-03T16:54:51.272Z" }, - { url = "https://files.pythonhosted.org/packages/2f/16/0dcc56cb6d3335c1671a2258f5d2cb8267c9a2260e27fde53cbfb1b3540a/sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:32fe6a41ad97302db2931f05bb91abbcc65b5ce4c675cd44b972428dd2947700", size = 3289602, upload-time = "2026-04-03T16:56:57.63Z" }, - { url = "https://files.pythonhosted.org/packages/51/6c/f8ab6fb04470a133cd80608db40aa292e6bae5f162c3a3d4ab19544a67af/sqlalchemy-2.0.49-cp311-cp311-win32.whl", hash = "sha256:46d51518d53edfbe0563662c96954dc8fcace9832332b914375f45a99b77cc9a", size = 2119044, upload-time = "2026-04-03T17:00:53.455Z" }, - { url = "https://files.pythonhosted.org/packages/c4/59/55a6d627d04b6ebb290693681d7683c7da001eddf90b60cfcc41ee907978/sqlalchemy-2.0.49-cp311-cp311-win_amd64.whl", hash = "sha256:951d4a210744813be63019f3df343bf233b7432aadf0db54c75802247330d3af", size = 2143642, upload-time = "2026-04-03T17:00:54.769Z" }, - { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, + { url = "https://files.pythonhosted.org/packages/e3/81/15d7c161c9ddf0900b076b55345872ed04ff1ed6a0666e5e94ab44b0163c/sqlalchemy-2.0.44-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd", size = 2140517, upload-time = "2025-10-10T15:36:15.64Z" }, + { url = "https://files.pythonhosted.org/packages/d4/d5/4abd13b245c7d91bdf131d4916fd9e96a584dac74215f8b5bc945206a974/sqlalchemy-2.0.44-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa", size = 2130738, upload-time = "2025-10-10T15:36:16.91Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3c/8418969879c26522019c1025171cefbb2a8586b6789ea13254ac602986c0/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e", size = 3304145, upload-time = "2025-10-10T15:34:19.569Z" }, + { url = "https://files.pythonhosted.org/packages/94/2d/fdb9246d9d32518bda5d90f4b65030b9bf403a935cfe4c36a474846517cb/sqlalchemy-2.0.44-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e", size = 3304511, upload-time = "2025-10-10T15:47:05.088Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fb/40f2ad1da97d5c83f6c1269664678293d3fe28e90ad17a1093b735420549/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399", size = 3235161, upload-time = "2025-10-10T15:34:21.193Z" }, + { url = "https://files.pythonhosted.org/packages/95/cb/7cf4078b46752dca917d18cf31910d4eff6076e5b513c2d66100c4293d83/sqlalchemy-2.0.44-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b", size = 3261426, upload-time = "2025-10-10T15:47:07.196Z" }, + { url = "https://files.pythonhosted.org/packages/f8/3b/55c09b285cb2d55bdfa711e778bdffdd0dc3ffa052b0af41f1c5d6e582fa/sqlalchemy-2.0.44-cp311-cp311-win32.whl", hash = "sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3", size = 2105392, upload-time = "2025-10-10T15:38:20.051Z" }, + { url = "https://files.pythonhosted.org/packages/c7/23/907193c2f4d680aedbfbdf7bf24c13925e3c7c292e813326c1b84a0b878e/sqlalchemy-2.0.44-cp311-cp311-win_amd64.whl", hash = "sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5", size = 2130293, upload-time = "2025-10-10T15:38:21.601Z" }, + { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718, upload-time = "2025-10-10T15:29:45.32Z" }, ] [[package]] name = "sqlparse" -version = "0.5.5" +version = "0.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/40/edede8dd6977b0d3da179a342c198ed100dd2aba4be081861ee5911e4da4/sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", size = 84999, upload-time = "2024-12-10T12:05:30.728Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" }, ] [[package]] @@ -4015,20 +3908,20 @@ wheels = [ [[package]] name = "tabulate" -version = "0.10.0" +version = "0.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, ] [[package]] name = "tenacity" -version = "9.1.4" +version = "9.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, ] [[package]] @@ -4062,24 +3955,23 @@ wheels = [ [[package]] name = "tensordict" -version = "0.12.2" +version = "0.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cloudpickle" }, - { name = "importlib-metadata" }, - { name = "numpy" }, - { name = "orjson" }, - { name = "packaging" }, - { name = "pyvers" }, - { name = "torch", version = "2.8.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "cloudpickle", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "importlib-metadata", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "numpy", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "orjson", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pyvers", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/20/83/e3a4726d83d7ad4d3f5d56b1e00473dfa550ed73411b9f3fa1a039c8c56f/tensordict-0.12.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ae8c58dd32aacdd73ab13b021f6e00bee6c58cfb896936e11603c834e801c465", size = 888476, upload-time = "2026-04-20T15:11:22.168Z" }, - { url = "https://files.pythonhosted.org/packages/04/4f/ffb8514f584ad9f4cff40582929818b41a2fe810413183466b71cd784abe/tensordict-0.12.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:76bb01f9f0580bf0ca1210f7f6d4ef8d8bc4a4bf2458adbad4443c65191eedab", size = 531915, upload-time = "2026-04-20T15:11:24.094Z" }, - { url = "https://files.pythonhosted.org/packages/05/b7/78f7eada33d84c1de7bc632b159c4b9e468fc245d1bcf36e1d7e8ec98581/tensordict-0.12.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:3b43e6ce47a23c87335087ef862bd11d996161edc0ab7b8f08796fee297668e0", size = 536398, upload-time = "2026-04-20T15:11:25.494Z" }, - { url = "https://files.pythonhosted.org/packages/48/5f/0a2cfec89d0273632e70880f341427a25558666bf9e0a5c8e637fe95e3cc/tensordict-0.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae42ba5511d76698c1da2461805f9a6d6c2cfacd318289385bd841ed404edf3d", size = 584735, upload-time = "2026-04-20T15:11:26.995Z" }, + { url = "https://files.pythonhosted.org/packages/6c/c9/44d4106f288cef22962268b54ed2438afee32e4f8380f0ed91e7dacc9b80/tensordict-0.10.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:37af5d60593c2439d81c2dbb7d0caa0018c50a3063da18b1d4d8b7d7d0503ee0", size = 800435, upload-time = "2025-09-08T10:07:12.581Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7f/46b81cd2bf98860a6e4313605eccd45d44c7490dfd60b2124534d7efbe6e/tensordict-0.10.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:369c0a2dd3cbd9d0bcf98cc389486295e683d262bb57d4a07733cd56d936f4b2", size = 444486, upload-time = "2025-09-08T10:07:13.826Z" }, + { url = "https://files.pythonhosted.org/packages/41/c1/373677e2376c25f0b01ba46907fcae33268d371bcaae45026f6fed418b77/tensordict-0.10.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:bccb6a7d7f02a8c83ca41815943bfa284da7d28019ab4276135809bda5ba05a6", size = 447610, upload-time = "2025-09-08T10:07:15.304Z" }, + { url = "https://files.pythonhosted.org/packages/37/24/acc1f329605d5e57f33650b7bb3bd5bb39b0ba0ad86b1d06c2282b668004/tensordict-0.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:07f691f73eaefa40cf285266318caac54c7527afcd149646ed3dc1af2fc45c9d", size = 493474, upload-time = "2025-09-08T10:07:16.866Z" }, ] [[package]] @@ -4123,18 +4015,18 @@ name = "tensorflow-data-validation" version = "1.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "absl-py" }, - { name = "apache-beam", extra = ["gcp"] }, - { name = "joblib" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "protobuf" }, - { name = "pyarrow" }, - { name = "pyfarmhash" }, - { name = "six" }, - { name = "tensorflow" }, - { name = "tensorflow-metadata" }, - { name = "tfx-bsl" }, + { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "apache-beam", extra = ["gcp"], marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "joblib", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "numpy", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pandas", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pyarrow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pyfarmhash", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "six", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tfx-bsl", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/c9/d8/8b193132c8769d31d11e92b058cd6651b5d8cba1b91878665bdb7408260b/tensorflow_data_validation-1.16.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:b21fa86c61da5cee81b4d602953fea16878de4874eb6035bf7f3221cfeb91559", size = 20236896, upload-time = "2024-10-15T20:20:03.396Z" }, @@ -4157,9 +4049,9 @@ name = "tensorflow-metadata" version = "1.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "absl-py" }, - { name = "googleapis-common-protos" }, - { name = "protobuf" }, + { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "googleapis-common-protos", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/e0/57/393aa9dde72347cde9e01f665bac344f14adefd5c748be45b23aa5804f6d/tensorflow_metadata-1.16.1-py3-none-any.whl", hash = "sha256:2ce72ea31d78a00c0c74c6d465482335aa5cb2a3b2a104dedba0b258bc7bb18a", size = 28984, upload-time = "2024-10-09T19:57:12.683Z" }, @@ -4170,9 +4062,9 @@ name = "tensorflow-serving-api" version = "2.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "grpcio" }, - { name = "protobuf" }, - { name = "tensorflow" }, + { name = "grpcio", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/f6/6a/6e91fbca9593663edc368df59a5d57e5549048530ba42c6833b560e30cba/tensorflow_serving_api-2.16.1-py2.py3-none-any.whl", hash = "sha256:13f859ea45055d393acd4cd8b44283ac52ff2970051fb9b96a69e0a626f07992", size = 26539, upload-time = "2024-03-22T02:01:06.207Z" }, @@ -4183,16 +4075,16 @@ name = "tensorflow-transform" version = "1.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "absl-py" }, - { name = "apache-beam", extra = ["gcp"] }, - { name = "numpy" }, - { name = "protobuf" }, - { name = "pyarrow" }, - { name = "pydot" }, - { name = "tensorflow" }, - { name = "tensorflow-metadata" }, - { name = "tf-keras" }, - { name = "tfx-bsl" }, + { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "apache-beam", extra = ["gcp"], marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "numpy", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pyarrow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pydot", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tf-keras", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tfx-bsl", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/30/a4/7610ef37f429855bd832f98377715298f66478c8e16174e9330f10bd1eed/tensorflow_transform-1.16.0-py3-none-any.whl", hash = "sha256:a2138d6c052cb5ad30ca08191d8795d2059e86d6001b2cb5a3b00d567727d7f1", size = 451456, upload-time = "2024-10-28T22:32:45.384Z" }, @@ -4200,11 +4092,11 @@ wheels = [ [[package]] name = "termcolor" -version = "3.3.0" +version = "3.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } +sdist = { url = "https://files.pythonhosted.org/packages/87/56/ab275c2b56a5e2342568838f0d5e3e66a32354adcc159b495e374cda43f5/termcolor-3.2.0.tar.gz", hash = "sha256:610e6456feec42c4bcd28934a8c87a06c3fa28b01561d46aa09a9881b8622c58", size = 14423, upload-time = "2025-10-25T19:11:42.586Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, + { url = "https://files.pythonhosted.org/packages/f9/d5/141f53d7c1eb2a80e6d3e9a390228c3222c27705cbe7f048d3623053f3ca/termcolor-3.2.0-py3-none-any.whl", hash = "sha256:a10343879eba4da819353c55cb8049b0933890c2ebf9ad5d3ecd2bb32ea96ea6", size = 7698, upload-time = "2025-10-25T19:11:41.536Z" }, ] [[package]] @@ -4212,7 +4104,7 @@ name = "tf-keras" version = "2.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "tensorflow" }, + { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7c/63/59a4aee62ea8999850e4b3b5d94b60fe280ca93de60d0e2958066e24d6a7/tf_keras-2.16.0.tar.gz", hash = "sha256:db53891f1ac98197c2acced98cdca8c06ba8255655a6cb7eb95ed49676118280", size = 1259784, upload-time = "2024-03-09T02:28:18.742Z" } wheels = [ @@ -4224,16 +4116,16 @@ name = "tfx-bsl" version = "1.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "absl-py" }, - { name = "apache-beam", extra = ["gcp"] }, - { name = "google-api-python-client" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "protobuf" }, - { name = "pyarrow" }, - { name = "tensorflow" }, - { name = "tensorflow-metadata" }, - { name = "tensorflow-serving-api" }, + { name = "absl-py", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "apache-beam", extra = ["gcp"], marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "google-api-python-client", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "numpy", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pandas", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "protobuf", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "pyarrow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow-metadata", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "tensorflow-serving-api", marker = "sys_platform != 'darwin' or extra != 'extra-4-gigl-pyg27-torch28-cpu' or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/e5/e5/a123d09e160be09423544529883f59b89dcbfb3242218a535af2b23826f4/tfx_bsl-1.16.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:1c13ff8f4de36ceea598a5a06b9cccabb73c7b9792ca280b915abd24b6a141b5", size = 24141870, upload-time = "2024-10-14T19:08:53.096Z" }, @@ -4269,12 +4161,12 @@ resolution-markers = [ "platform_machine == 'arm64' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "fsspec", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "jinja2", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "networkx", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "sympy", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "typing-extensions", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "filelock", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, + { name = "fsspec", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, + { name = "jinja2", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, + { name = "networkx", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, + { name = "sympy", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "platform_machine == 'arm64' and sys_platform == 'darwin'" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:3d05017d19bc99741288e458888283a44b0ee881d53f05f72f8b1cfea8998122", upload-time = "2025-10-01T23:35:48Z" }, @@ -4336,17 +4228,6 @@ wheels = [ { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.8.0%2Bcu128-cp311-cp311-win_amd64.whl", hash = "sha256:34c55443aafd31046a7963b63d30bc3b628ee4a704f826796c865fdfd05bb596", upload-time = "2025-10-01T23:49:30Z" }, ] -[[package]] -name = "torch-cluster" -version = "1.6.3" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -dependencies = [ - { name = "scipy", marker = "sys_platform == 'darwin'" }, -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_cluster-1.6.3-cp311-cp311-macosx_10_9_universal2.whl" }, -] - [[package]] name = "torch-cluster" version = "1.6.3+pt28cpu" @@ -4395,14 +4276,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/d3/4dffd7300500465e0b4a2ae917dcb2ce771de0b9a772670365799a27c024/torch_geometric-2.7.0-py3-none-any.whl", hash = "sha256:6e0cd3ad824d484651ef5d308fc66c687bfcf5ba040d56d1e0fe0f81f365e292", size = 1275346, upload-time = "2025-10-15T20:48:01.949Z" }, ] -[[package]] -name = "torch-scatter" -version = "2.1.2" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_scatter-2.1.2-cp311-cp311-macosx_10_9_universal2.whl" }, -] - [[package]] name = "torch-scatter" version = "2.1.2+pt28cpu" @@ -4425,17 +4298,6 @@ wheels = [ { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_scatter-2.1.2%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, ] -[[package]] -name = "torch-sparse" -version = "0.6.18" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -dependencies = [ - { name = "scipy", marker = "sys_platform == 'darwin'" }, -] -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_sparse-0.6.18-cp311-cp311-macosx_11_0_universal2.whl" }, -] - [[package]] name = "torch-sparse" version = "0.6.18+pt28cpu" @@ -4464,14 +4326,6 @@ wheels = [ { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcu128/torch_sparse-0.6.18%2Bpt28cu128-cp311-cp311-win_amd64.whl" }, ] -[[package]] -name = "torch-spline-conv" -version = "1.2.2" -source = { registry = "https://data.pyg.org/whl/torch-2.8.0+cpu.html" } -wheels = [ - { url = "https://data.pyg.org/whl/torch-2.8.0%2Bcpu/torch_spline_conv-1.2.2-cp311-cp311-macosx_10_9_universal2.whl" }, -] - [[package]] name = "torch-spline-conv" version = "1.2.2+pt28cpu" @@ -4499,11 +4353,10 @@ name = "torchmetrics" version = "1.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "lightning-utilities" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "torch", version = "2.8.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, - { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'arm64' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "lightning-utilities", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "numpy", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "packaging", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "torch", version = "2.8.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (extra == 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, { name = "torch", version = "2.8.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "extra == 'extra-4-gigl-pyg27-torch28-cu128'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/01/b6c344ac04b53ebe3759ba938f1406775fe7649c44ba2e27e467be4e6fe9/torchmetrics-1.0.3.tar.gz", hash = "sha256:1c20ea2f0db434334e88da6c015ddf936d43379bfb403e9dc2a7272b0eab453c", size = 432173, upload-time = "2023-08-08T15:50:49.966Z" } @@ -4513,26 +4366,26 @@ wheels = [ [[package]] name = "torchrec" -version = "1.5.0+cpu" +version = "1.3.0+cpu" source = { registry = "https://download.pytorch.org/whl/cpu" } resolution-markers = [ "sys_platform != 'darwin'", ] dependencies = [ - { name = "fbgemm-gpu", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" } }, - { name = "iopath" }, - { name = "pyre-extensions" }, - { name = "tensordict" }, - { name = "torchmetrics" }, - { name = "tqdm" }, + { name = "fbgemm-gpu", version = "1.3.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform != 'darwin'" }, + { name = "iopath", marker = "sys_platform != 'darwin'" }, + { name = "pyre-extensions", marker = "sys_platform != 'darwin'" }, + { name = "tensordict", marker = "sys_platform != 'darwin'" }, + { name = "torchmetrics", marker = "sys_platform != 'darwin'" }, + { name = "tqdm", marker = "sys_platform != 'darwin'" }, ] wheels = [ - { url = "https://download.pytorch.org/whl/cpu/torchrec-1.5.0%2Bcpu-py3-none-any.whl", hash = "sha256:0625095099a0b0b9edd8c7777b8a83fe5e2ed9c67529e0fb6bf1b71d2d7f392f", upload-time = "2026-02-16T15:11:21Z" }, + { url = "https://download.pytorch.org/whl/cpu/torchrec-1.3.0%2Bcpu-py3-none-any.whl", hash = "sha256:be2b572625792feac1656afcac19e35448df5447d215575a4b8cb22d9220d2cf", upload-time = "2025-09-17T07:14:32Z" }, ] [[package]] name = "torchrec" -version = "1.5.0+cu128" +version = "1.3.0+cu128" source = { registry = "https://download.pytorch.org/whl/cu128" } dependencies = [ { name = "fbgemm-gpu", version = "1.3.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } }, @@ -4543,36 +4396,38 @@ dependencies = [ { name = "tqdm" }, ] wheels = [ - { url = "https://download.pytorch.org/whl/cu128/torchrec-1.5.0%2Bcu128-py3-none-any.whl", hash = "sha256:966421c469f4c3cad5d3800e6f4f49fcfcc33e14a39801c465f00f335efc4e75", upload-time = "2026-02-16T15:11:35Z" }, + { url = "https://download.pytorch.org/whl/cu128/torchrec-1.3.0%2Bcu128-py3-none-any.whl", hash = "sha256:6de7e4a70a6e95815a8f06b1dec4d982cea4d32fa7d86a10a8bb4c52b8a749b9", upload-time = "2025-09-17T07:14:37Z" }, ] [[package]] name = "tornado" -version = "6.5.5" +version = "6.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" } +sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" }, - { url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" }, - { url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" }, - { url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" }, - { url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" }, - { url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" }, - { url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" }, - { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" }, + { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" }, + { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" }, + { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" }, + { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" }, + { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" }, ] [[package]] name = "tqdm" -version = "4.67.3" +version = "4.67.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, ] [[package]] @@ -4597,11 +4452,11 @@ wheels = [ [[package]] name = "types-protobuf" -version = "7.34.1.20260408" +version = "6.32.1.20250918" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/b1/4521e68c2cc17703d80eb42796751345376dd4c706f84007ef5e7c707774/types_protobuf-7.34.1.20260408.tar.gz", hash = "sha256:e2c0a0430e08c75b52671a6f0035abfdcc791aad12af16274282de1b721758ab", size = 68835, upload-time = "2026-04-08T04:26:43.613Z" } +sdist = { url = "https://files.pythonhosted.org/packages/69/5a/bd06c2dbb77ebd4ea764473c9c4c014c7ba94432192cb965a274f8544b9d/types_protobuf-6.32.1.20250918.tar.gz", hash = "sha256:44ce0ae98475909ca72379946ab61a4435eec2a41090821e713c17e8faf5b88f", size = 63780, upload-time = "2025-09-18T02:50:39.391Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/b5/0bc9874d89c58fb0ce851e150055ce732d254dbb10b06becbc7635d0d635/types_protobuf-7.34.1.20260408-py3-none-any.whl", hash = "sha256:ebbcd4e27b145aef6a59bc0cb6c013b3528151c1ba5e7f7337aeee355d276a5e", size = 86012, upload-time = "2026-04-08T04:26:42.566Z" }, + { url = "https://files.pythonhosted.org/packages/37/5a/8d93d4f4af5dc3dd62aa4f020deae746b34b1d94fb5bee1f776c6b7e9d6c/types_protobuf-6.32.1.20250918-py3-none-any.whl", hash = "sha256:22ba6133d142d11cc34d3788ad6dead2732368ebb0406eaa7790ea6ae46c8d0b", size = 77885, upload-time = "2025-09-18T02:50:38.028Z" }, ] [[package]] @@ -4615,20 +4470,20 @@ wheels = [ [[package]] name = "types-pytz" -version = "2026.1.1.20260408" +version = "2025.2.0.20250809" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/b7/33f5a4f29b1f285b99ff79a607751a7996194cbb98705e331dab7a2daa28/types_pytz-2026.1.1.20260408.tar.gz", hash = "sha256:89b6a34b9198ea2a4b98a9d15cbca987053f52a105fd44f7ce3789cae4349408", size = 10788, upload-time = "2026-04-08T04:28:14.54Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/e2/c774f754de26848f53f05defff5bb21dd9375a059d1ba5b5ea943cf8206e/types_pytz-2025.2.0.20250809.tar.gz", hash = "sha256:222e32e6a29bb28871f8834e8785e3801f2dc4441c715cd2082b271eecbe21e5", size = 10876, upload-time = "2025-08-09T03:14:17.453Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/90/12c059e6bb330a22d9cc97daf027ac7fb7f50fbf518e4d88185b4d39120e/types_pytz-2026.1.1.20260408-py3-none-any.whl", hash = "sha256:c7e4dec76221fb7d0c97b91ad8561d689bebe39b6bcb7b728387e7ffd8cde788", size = 10124, upload-time = "2026-04-08T04:28:13.353Z" }, + { url = "https://files.pythonhosted.org/packages/db/d0/91c24fe54e565f2344d7a6821e6c6bb099841ef09007ea6321a0bac0f808/types_pytz-2025.2.0.20250809-py3-none-any.whl", hash = "sha256:4f55ed1b43e925cf851a756fe1707e0f5deeb1976e15bf844bcaa025e8fbd0db", size = 10095, upload-time = "2025-08-09T03:14:16.674Z" }, ] [[package]] name = "types-pyyaml" -version = "6.0.12.20260408" +version = "6.0.12.20250915" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/74/73/b759b1e413c31034cc01ecdfb96b38115d0ab4db55a752a3929f0cd449fd/types_pyyaml-6.0.12.20260408.tar.gz", hash = "sha256:92a73f2b8d7f39ef392a38131f76b970f8c66e4c42b3125ae872b7c93b556307", size = 17735, upload-time = "2026-04-08T04:30:50.974Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/f0/c391068b86abb708882c6d75a08cd7d25b2c7227dab527b3a3685a3c635b/types_pyyaml-6.0.12.20260408-py3-none-any.whl", hash = "sha256:fbc42037d12159d9c801ebfcc79ebd28335a7c13b08a4cfbc6916df78fee9384", size = 20339, upload-time = "2026-04-08T04:30:50.113Z" }, + { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" }, ] [[package]] @@ -4678,8 +4533,8 @@ name = "typing-inspect" version = "0.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, + { name = "mypy-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, + { name = "typing-extensions", marker = "(sys_platform != 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-gigl-pyg27-torch28-cu128') or (extra != 'extra-4-gigl-pyg27-torch28-cpu' and extra == 'extra-4-gigl-pyg27-torch28-cu128')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } wheels = [ @@ -4700,11 +4555,11 @@ wheels = [ [[package]] name = "tzdata" -version = "2026.2" +version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, ] [[package]] @@ -4730,35 +4585,34 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.3" +version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] [[package]] name = "virtualenv" -version = "21.2.4" +version = "20.35.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, - { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/98/3a7e644e19cb26133488caff231be390579860bbbb3da35913c49a1d0a46/virtualenv-21.2.4.tar.gz", hash = "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada", size = 5850742, upload-time = "2026-04-14T22:15:31.438Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/8d/edd0bd910ff803c308ee9a6b7778621af0d10252219ad9f19ef4d4982a61/virtualenv-21.2.4-py3-none-any.whl", hash = "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac", size = 5831232, upload-time = "2026-04-14T22:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, ] [[package]] name = "wcwidth" -version = "0.6.0" +version = "0.2.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" }, + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, ] [[package]] @@ -4781,69 +4635,64 @@ wheels = [ [[package]] name = "websockets" -version = "16.0" +version = "15.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, - { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, - { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, - { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, - { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, - { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, - { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, - { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, - { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, - { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, - { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] [[package]] name = "werkzeug" -version = "3.1.8" +version = "3.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", size = 226459, upload-time = "2026-04-02T18:49:12.72Z" }, + { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, ] [[package]] name = "wheel" -version = "0.47.0" +version = "0.45.1" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/39/62/75f18a0f03b4219c456652c7780e4d749b929eb605c098ce3a5b6b6bc081/wheel-0.47.0.tar.gz", hash = "sha256:cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3", size = 63854, upload-time = "2026-04-22T15:51:27.727Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl", hash = "sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced", size = 32218, upload-time = "2026-04-22T15:51:26.296Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" }, ] [[package]] name = "wrapt" -version = "2.1.2" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/19/5e5bcd855d808892fe02d49219f97a50f64cd6d8313d75df3494ee97b1a3/wrapt-2.0.0.tar.gz", hash = "sha256:35a542cc7a962331d0279735c30995b024e852cf40481e384fd63caaa391cbb9", size = 81722, upload-time = "2025-10-19T23:47:54.07Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/81/60c4471fce95afa5922ca09b88a25f03c93343f759aae0f31fb4412a85c7/wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb", size = 60666, upload-time = "2026-03-06T02:52:58.934Z" }, - { url = "https://files.pythonhosted.org/packages/6b/be/80e80e39e7cb90b006a0eaf11c73ac3a62bbfb3068469aec15cc0bc795de/wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d", size = 61601, upload-time = "2026-03-06T02:53:00.487Z" }, - { url = "https://files.pythonhosted.org/packages/b0/be/d7c88cd9293c859fc74b232abdc65a229bb953997995d6912fc85af18323/wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894", size = 114057, upload-time = "2026-03-06T02:52:44.08Z" }, - { url = "https://files.pythonhosted.org/packages/ea/25/36c04602831a4d685d45a93b3abea61eca7fe35dab6c842d6f5d570ef94a/wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842", size = 116099, upload-time = "2026-03-06T02:54:56.74Z" }, - { url = "https://files.pythonhosted.org/packages/5c/4e/98a6eb417ef551dc277bec1253d5246b25003cf36fdf3913b65cb7657a56/wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8", size = 112457, upload-time = "2026-03-06T02:53:52.842Z" }, - { url = "https://files.pythonhosted.org/packages/cb/a6/a6f7186a5297cad8ec53fd7578533b28f795fdf5372368c74bd7e6e9841c/wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6", size = 115351, upload-time = "2026-03-06T02:53:32.684Z" }, - { url = "https://files.pythonhosted.org/packages/97/6f/06e66189e721dbebd5cf20e138acc4d1150288ce118462f2fcbff92d38db/wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9", size = 111748, upload-time = "2026-03-06T02:53:08.455Z" }, - { url = "https://files.pythonhosted.org/packages/ef/43/4808b86f499a51370fbdbdfa6cb91e9b9169e762716456471b619fca7a70/wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15", size = 113783, upload-time = "2026-03-06T02:53:02.02Z" }, - { url = "https://files.pythonhosted.org/packages/91/2c/a3f28b8fa7ac2cefa01cfcaca3471f9b0460608d012b693998cd61ef43df/wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b", size = 57977, upload-time = "2026-03-06T02:53:27.844Z" }, - { url = "https://files.pythonhosted.org/packages/3f/c3/2b1c7bd07a27b1db885a2fab469b707bdd35bddf30a113b4917a7e2139d2/wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1", size = 60336, upload-time = "2026-03-06T02:54:28.104Z" }, - { url = "https://files.pythonhosted.org/packages/ec/5c/76ece7b401b088daa6503d6264dd80f9a727df3e6042802de9a223084ea2/wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a", size = 58756, upload-time = "2026-03-06T02:53:16.319Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, + { url = "https://files.pythonhosted.org/packages/12/8f/8e4c8b6da60b4205191d588cbac448fb9ff4f5ed89f4e555dc4813ab30cf/wrapt-2.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b7e221abb6c5387819db9323dac3c875b459695057449634f1111955d753c621", size = 77433, upload-time = "2025-10-19T23:45:42.543Z" }, + { url = "https://files.pythonhosted.org/packages/22/9a/01a29ccb029aa8e78241f8b53cb89ae8826c240129abbbb6ebba3416eff9/wrapt-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1147a84c8fc852426580af8b6e33138461ddbc65aa459a25ea539374d32069fa", size = 60641, upload-time = "2025-10-19T23:45:43.866Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ec/e058997971428b7665b5c3665a55b18bb251ea7e08d002925e3ca017c020/wrapt-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d6691d4a711504a0bc10de789842ad6ac627bed22937b10f37a1211a8ab7bb3", size = 61526, upload-time = "2025-10-19T23:45:44.839Z" }, + { url = "https://files.pythonhosted.org/packages/70/c3/c82263503f554715aa1847e85dc75a69631a54e9d7ab0f1a55e34a22d44a/wrapt-2.0.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f460e1eb8e75a17c3918c8e35ba57625721eef2439ef0bcf05304ac278a65e1d", size = 114069, upload-time = "2025-10-19T23:45:47.223Z" }, + { url = "https://files.pythonhosted.org/packages/dc/97/d95e88a3a1bc2890a1aa47880c2762cf0eb6d231b5a64048e351cec6f071/wrapt-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:12c37784b77bf043bf65cc96c7195a5db474b8e54173208af076bdbb61df7b3e", size = 116109, upload-time = "2025-10-19T23:45:48.252Z" }, + { url = "https://files.pythonhosted.org/packages/dc/36/cba0bf954f2303897b80fa5342499b43f8c5201110dddf0d578d6841b149/wrapt-2.0.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75e5c049eb583835f7a0e0e311d9dde9bfbaac723a6dd89d052540f9b2809977", size = 112500, upload-time = "2025-10-19T23:45:45.838Z" }, + { url = "https://files.pythonhosted.org/packages/d7/2b/8cb88e63bec989f641d208acb3fd198bfdbbb4ef7dfb71f0cac3c90b07a9/wrapt-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e50bcbd5b65dac21b82319fcf18486e6ac439947e9305034b00704eb7405f553", size = 115356, upload-time = "2025-10-19T23:45:49.249Z" }, + { url = "https://files.pythonhosted.org/packages/bb/60/a6d5fb94648cd430648705bef9f4241bd22ead123ead552b6d2873ad5240/wrapt-2.0.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:06b78cb6b9320f57737a52fede882640d93cface98332d1a3df0c5696ec9ae9f", size = 111754, upload-time = "2025-10-19T23:45:51.21Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/1963854edf0592ae806307899dc7bf891e76cec19e598f55845c94603a65/wrapt-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c8349ebfc3cd98bc9105e0112dd8c8ac1f3c7cb5601f9d02248cae83a63f748", size = 113789, upload-time = "2025-10-19T23:45:52.473Z" }, + { url = "https://files.pythonhosted.org/packages/62/ec/4b1d76cb6d96ac511aaaa92efc57f528e57f06082a595b8b2663fcdb0f20/wrapt-2.0.0-cp311-cp311-win32.whl", hash = "sha256:028f19ec29e204fe725139d4a8b09f77ecfb64f8f02b7ab5ee822c85e330b68b", size = 57954, upload-time = "2025-10-19T23:45:57.03Z" }, + { url = "https://files.pythonhosted.org/packages/d4/cf/df8ff9bd64d4a75f9a9f6c1c93480a51904d0c9bd71c11994301c47d8a33/wrapt-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:c6961f05e58d919153ba311b397b7b904b907132b7b8344dde47865d4bb5ec89", size = 60308, upload-time = "2025-10-19T23:45:54.314Z" }, + { url = "https://files.pythonhosted.org/packages/69/d8/61e245fe387d58d84b3f913d5da9d909c4f239b887db692a05105aaf2a1b/wrapt-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:be7e316c2accd5a31dbcc230de19e2a846a325f8967fdea72704d00e38e6af06", size = 58822, upload-time = "2025-10-19T23:45:55.772Z" }, + { url = "https://files.pythonhosted.org/packages/00/5c/c34575f96a0a038579683c7f10fca943c15c7946037d1d254ab9db1536ec/wrapt-2.0.0-py3-none-any.whl", hash = "sha256:02482fb0df89857e35427dfb844319417e14fae05878f295ee43fa3bf3b15502", size = 43998, upload-time = "2025-10-19T23:47:52.858Z" }, ] [[package]] @@ -4876,43 +4725,41 @@ wheels = [ [[package]] name = "yarl" -version = "1.23.0" +version = "1.22.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/aa/60da938b8f0997ba3a911263c40d82b6f645a67902a490b46f3355e10fae/yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99", size = 123641, upload-time = "2026-03-01T22:04:42.841Z" }, - { url = "https://files.pythonhosted.org/packages/24/84/e237607faf4e099dbb8a4f511cfd5efcb5f75918baad200ff7380635631b/yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c", size = 86248, upload-time = "2026-03-01T22:04:44.757Z" }, - { url = "https://files.pythonhosted.org/packages/b2/0d/71ceabc14c146ba8ee3804ca7b3d42b1664c8440439de5214d366fec7d3a/yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432", size = 85988, upload-time = "2026-03-01T22:04:46.365Z" }, - { url = "https://files.pythonhosted.org/packages/8c/6c/4a90d59c572e46b270ca132aca66954f1175abd691f74c1ef4c6711828e2/yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", size = 100566, upload-time = "2026-03-01T22:04:47.639Z" }, - { url = "https://files.pythonhosted.org/packages/49/fb/c438fb5108047e629f6282a371e6e91cf3f97ee087c4fb748a1f32ceef55/yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", size = 92079, upload-time = "2026-03-01T22:04:48.925Z" }, - { url = "https://files.pythonhosted.org/packages/d9/13/d269aa1aed3e4f50a5a103f96327210cc5fa5dd2d50882778f13c7a14606/yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", size = 108741, upload-time = "2026-03-01T22:04:50.838Z" }, - { url = "https://files.pythonhosted.org/packages/85/fb/115b16f22c37ea4437d323e472945bea97301c8ec6089868fa560abab590/yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", size = 108099, upload-time = "2026-03-01T22:04:52.499Z" }, - { url = "https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", size = 102678, upload-time = "2026-03-01T22:04:55.176Z" }, - { url = "https://files.pythonhosted.org/packages/85/59/cd98e556fbb2bf8fab29c1a722f67ad45c5f3447cac798ab85620d1e70af/yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", size = 100803, upload-time = "2026-03-01T22:04:56.588Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c0/b39770b56d4a9f0bb5f77e2f1763cd2d75cc2f6c0131e3b4c360348fcd65/yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", size = 100163, upload-time = "2026-03-01T22:04:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/e7/64/6980f99ab00e1f0ff67cb84766c93d595b067eed07439cfccfc8fb28c1a6/yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", size = 93859, upload-time = "2026-03-01T22:05:00.268Z" }, - { url = "https://files.pythonhosted.org/packages/38/69/912e6c5e146793e5d4b5fe39ff5b00f4d22463dfd5a162bec565ac757673/yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", size = 108202, upload-time = "2026-03-01T22:05:02.273Z" }, - { url = "https://files.pythonhosted.org/packages/59/97/35ca6767524687ad64e5f5c31ad54bc76d585585a9fcb40f649e7e82ffed/yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", size = 99866, upload-time = "2026-03-01T22:05:03.597Z" }, - { url = "https://files.pythonhosted.org/packages/d3/1c/1a3387ee6d73589f6f2a220ae06f2984f6c20b40c734989b0a44f5987308/yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", size = 107852, upload-time = "2026-03-01T22:05:04.986Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b8/35c0750fcd5a3f781058bfd954515dd4b1eab45e218cbb85cf11132215f1/yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", size = 102919, upload-time = "2026-03-01T22:05:06.397Z" }, - { url = "https://files.pythonhosted.org/packages/e5/1c/9a1979aec4a81896d597bcb2177827f2dbee3f5b7cc48b2d0dadb644b41d/yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5", size = 82602, upload-time = "2026-03-01T22:05:08.444Z" }, - { url = "https://files.pythonhosted.org/packages/93/22/b85eca6fa2ad9491af48c973e4c8cf6b103a73dbb271fe3346949449fca0/yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46", size = 87461, upload-time = "2026-03-01T22:05:10.145Z" }, - { url = "https://files.pythonhosted.org/packages/93/95/07e3553fe6f113e6864a20bdc53a78113cda3b9ced8784ee52a52c9f80d8/yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928", size = 82336, upload-time = "2026-03-01T22:05:11.554Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, + { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, + { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, + { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, + { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, + { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, + { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, + { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, + { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] [[package]] name = "zipp" -version = "3.23.1" +version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, ] [[package]] From 1ea0a296c633b981951cf64d3469fe46b48b7200 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 22:12:53 +0000 Subject: [PATCH 093/148] remove stale changes --- .../run_command_on_active_checkout.yaml | 2 +- CMakeLists.txt | 130 ------------------ containers/Dockerfile.dataflow.src | 5 - gigl/csrc/__init__.py | 0 gigl/dep_vars.env | 6 +- gigl/orchestration/Dockerfile.customer_src | 2 +- requirements/install_py_deps.sh | 2 + tests/unit/cpp/CMakeLists.txt | 52 ------- tests/unit/cpp/infrastructure_test.cpp | 12 -- 9 files changed, 7 insertions(+), 204 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 gigl/csrc/__init__.py delete mode 100644 tests/unit/cpp/CMakeLists.txt delete mode 100644 tests/unit/cpp/infrastructure_test.cpp diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index c93f1ad76..d0e407f02 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 entrypoint: /bin/bash args: - -c diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index a459963db..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,130 +0,0 @@ -cmake_minimum_required(VERSION 3.18) -project(gigl_csrc CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -# CMP0104: CMake 3.18+ warns when enable_language(CUDA) is called without -# CMAKE_CUDA_ARCHITECTURES being set. Set it to OFF to tell CMake not to inject -# any -gencode flags — Torch provides a comprehensive arch list via TORCH_LIBRARIES. -if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18") - cmake_policy(SET CMP0104 NEW) - set(CMAKE_CUDA_ARCHITECTURES OFF) -endif() - -# Centralise CUDA language enablement so CMAKE_CUDA_STANDARD 17 is always set -# regardless of which detection path finds the compiler. -macro(_enable_cuda) - enable_language(CUDA) - set(CMAKE_CUDA_STANDARD 17) - set(CMAKE_CUDA_STANDARD_REQUIRED ON) -endmacro() - -# Enable CUDA only when the toolkit is present; allows the same CMakeLists.txt -# to build on CPU-only machines without requiring nvcc. -include(CheckLanguage) -check_language(CUDA) -if(CMAKE_CUDA_COMPILER) - _enable_cuda() -else() - # find_package(Torch) internally calls enable_language(CUDA) when torch was built with - # CUDA support, which requires CMAKE_CUDA_COMPILER to be set. Provide the standard - # install path as a hint so nvcc is found even when /usr/local/cuda/bin is not on PATH. - find_program(CMAKE_CUDA_COMPILER nvcc HINTS /usr/local/cuda/bin) - if(CMAKE_CUDA_COMPILER) - _enable_cuda() - endif() -endif() - -find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) - -# Locate pybind11 and torch cmake configs by scanning CMAKE_PREFIX_PATH, which -# both scikit-build-core and the Makefile set to the active environment's -# site-packages directory. -foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) - if(NOT pybind11_DIR AND EXISTS "${_prefix}/pybind11/share/cmake/pybind11") - set(pybind11_DIR "${_prefix}/pybind11/share/cmake/pybind11") - endif() - if(NOT TORCH_CMAKE_PREFIX AND EXISTS "${_prefix}/torch/share/cmake") - set(TORCH_CMAKE_PREFIX "${_prefix}/torch/share/cmake") - endif() -endforeach() - -if(NOT pybind11_DIR) - message(FATAL_ERROR "Cannot find pybind11 cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") -endif() -if(NOT TORCH_CMAKE_PREFIX) - message(FATAL_ERROR "Cannot find torch cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") -endif() - -find_package(pybind11 CONFIG REQUIRED) -find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") - -# torch_python provides the pybind11 type casters for at::Tensor. It is not -# included in TORCH_LIBRARIES but is required for extensions that pass tensors -# across the Python/C++ boundary. -# TORCH_INSTALL_PREFIX is set to /torch by TorchConfig.cmake. -find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_INSTALL_PREFIX}/lib" REQUIRED) - - -set(GIGL_COMPILE_FLAGS - -O3 -g -Wall -Wextra -Wno-unused-parameter -) -# nvcc does not accept bare -Wall/-Wextra; wrap them with -Xcompiler for CUDA sources. -set(GIGL_COMPILE_FLAGS_CUDA - -O3 -Xcompiler=-g,-Wall,-Wextra,-Wno-unused-parameter -) - -# --------------------------------------------------------------------------- -# Extension modules — auto-discovered. -# Files named python_*.cpp under gigl/csrc/ are compiled as pybind11 extension -# modules. The companion .cpp (without the "python_" prefix) is included -# automatically when present. This mirrors the convention from the old -# build_cpp_extensions.py: no changes here are needed to add new extensions. -# --------------------------------------------------------------------------- - -if(CMAKE_CUDA_COMPILER) - file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/gigl/csrc/python_*.cpp" - "${CMAKE_SOURCE_DIR}/gigl/csrc/python_*.cu" - ) -else() - file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/gigl/csrc/python_*.cpp" - ) -endif() - -option(GIGL_BUILD_TESTS "Build C++ unit tests (used by make unit_test_cpp)" OFF) - -foreach(_py_src IN LISTS _PYTHON_SRCS) - get_filename_component(_dir "${_py_src}" DIRECTORY) - get_filename_component(_stem "${_py_src}" NAME_WE) - string(REGEX REPLACE "^python_" "" _name "${_stem}") - - set(_sources "${_py_src}") - if(EXISTS "${_dir}/${_name}.cpp") - list(APPEND _sources "${_dir}/${_name}.cpp") - endif() - if(CMAKE_CUDA_COMPILER AND EXISTS "${_dir}/${_name}.cu") - list(APPEND _sources "${_dir}/${_name}.cu") - endif() - - file(RELATIVE_PATH _rel_dir "${CMAKE_SOURCE_DIR}" "${_dir}") - - pybind11_add_module("${_name}" ${_sources}) - target_link_libraries("${_name}" PRIVATE "${TORCH_LIBRARIES}" "${TORCH_PYTHON_LIBRARY}") - target_compile_options("${_name}" PRIVATE - $<$:${GIGL_COMPILE_FLAGS}> - $<$:${GIGL_COMPILE_FLAGS_CUDA}> - ) - # TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. - # PyTorch's own build system sets this; we must define it explicitly here. - target_compile_definitions("${_name}" PRIVATE "TORCH_EXTENSION_NAME=${_name}") - install(TARGETS "${_name}" DESTINATION "${_rel_dir}") -endforeach() - -if(GIGL_BUILD_TESTS) - enable_testing() - add_subdirectory(tests/unit/cpp) -endif() diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index 056158941..b5d29c7f0 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -5,12 +5,7 @@ FROM $BASE_IMAGE # Copy the source WORKDIR /gigl -# scikit-build-core needs CMakeLists.txt (build definition), MANIFEST.in (sdist source list), -# and README.md (required by pyproject.toml's readme field) before `uv pip install -e .` -# triggers the CMake build. Without these, the install will error at configure time. -COPY CMakeLists.txt CMakeLists.txt COPY MANIFEST.in MANIFEST.in -COPY README.md README.md COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock COPY gigl/dep_vars.env gigl/dep_vars.env diff --git a/gigl/csrc/__init__.py b/gigl/csrc/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index ec535c24b..85ef4d21b 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:3738af6cca02750514278cb63c98c88d07c45f7b.99.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 diff --git a/gigl/orchestration/Dockerfile.customer_src b/gigl/orchestration/Dockerfile.customer_src index 868e6279f..d7bf6947d 100644 --- a/gigl/orchestration/Dockerfile.customer_src +++ b/gigl/orchestration/Dockerfile.customer_src @@ -10,4 +10,4 @@ WORKDIR /gigl COPY . . # Find out if there is 'setup.py' or 'pyproject.toml' in the current directory, if so install it -RUN if [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then uv pip install scikit-build-core pybind11 && uv pip install -e .; fi +RUN if [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then uv pip install -e .; fi diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index 1cd491b98..3cdafc9c0 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -45,10 +45,12 @@ has_cuda_driver() { is_running_on_mac() { [ "$(uname)" == "Darwin" ] + return $? } is_running_on_m1_mac() { [ "$(uname)" == "Darwin" ] && [ $(uname -m) == 'arm64' ] + return $? } ### Installation Functions ### diff --git a/tests/unit/cpp/CMakeLists.txt b/tests/unit/cpp/CMakeLists.txt deleted file mode 100644 index 10b9520cf..000000000 --- a/tests/unit/cpp/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -include(CheckLanguage) -check_language(CUDA) -if(CMAKE_CUDA_COMPILER) - enable_language(CUDA) - set(CMAKE_CUDA_STANDARD 17) - set(CMAKE_CUDA_STANDARD_REQUIRED ON) -endif() - -# --------------------------------------------------------------------------- -# GoogleTest via FetchContent -# --------------------------------------------------------------------------- -include(FetchContent) -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.14.0 - GIT_SHALLOW TRUE -) -# Prevent GoogleTest from overriding the compiler's runtime on Windows -# (no-op on Linux/Mac, but required for portable CMake config). -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - -# Required for add_test() to register tests with CTest. -enable_testing() - -# --------------------------------------------------------------------------- -# Auto-discover test targets -# --------------------------------------------------------------------------- -# Any file named *_test.cpp in this directory (or subdirectories) is -# automatically compiled into its own test binary and registered with CTest. -# To add a new test suite, drop a *_test.cpp file here — no changes to this -# file required. This matches the *_test.py convention used for Python tests. -if(CMAKE_CUDA_COMPILER) - file(GLOB_RECURSE TEST_SOURCES "*_test.cpp" "*_test.cu") -else() - file(GLOB_RECURSE TEST_SOURCES "*_test.cpp") -endif() - -foreach(test_source ${TEST_SOURCES}) - # Derive a unique binary name from the path relative to this directory, e.g.: - # ppr_forward_push_test.cpp → ppr_forward_push_test - # sampling/ppr_forward_push_test.cpp → sampling_ppr_forward_push_test - file(RELATIVE_PATH _rel "${CMAKE_CURRENT_SOURCE_DIR}" "${test_source}") - string(REPLACE "/" "_" test_name "${_rel}") - string(REGEX REPLACE "\\.[^.]+$" "" test_name "${test_name}") - add_executable(${test_name} ${test_source}) - target_link_libraries(${test_name} GTest::gtest_main) - # add_test registers the binary with CTest. Each *_test binary is one - # CTest entry; GoogleTest itself reports individual TEST() results inside it. - add_test(NAME ${test_name} COMMAND ${test_name}) -endforeach() diff --git a/tests/unit/cpp/infrastructure_test.cpp b/tests/unit/cpp/infrastructure_test.cpp deleted file mode 100644 index eb3c1aa3d..000000000 --- a/tests/unit/cpp/infrastructure_test.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// Placeholder C++ unit test. -// -// This file exists to verify that the GoogleTest infrastructure compiles and -// runs end-to-end. - -#include - -// A trivial sanity-check test — if this fails, something is very wrong with -// the build environment itself. -TEST(PlaceholderTest, BasicArithmetic) { - EXPECT_EQ(1 + 1, 2); -} From d1dd8e3d9661513c3a7d65b28a802d9a04d62a27 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 22:15:59 +0000 Subject: [PATCH 094/148] remove stale files --- gigl-core/src/gigl_core/__init__.py | 11 ---------- gigl-core/src/gigl_core/ppr_forward_push.pyi | 22 -------------------- gigl-core/src/gigl_core/py.typed | 0 3 files changed, 33 deletions(-) delete mode 100644 gigl-core/src/gigl_core/ppr_forward_push.pyi delete mode 100644 gigl-core/src/gigl_core/py.typed diff --git a/gigl-core/src/gigl_core/__init__.py b/gigl-core/src/gigl_core/__init__.py index 7bf8c9987..e69de29bb 100644 --- a/gigl-core/src/gigl_core/__init__.py +++ b/gigl-core/src/gigl_core/__init__.py @@ -1,11 +0,0 @@ -try: - from gigl_core.ppr_forward_push import PPRForwardPushState -except ImportError as e: - raise ImportError( - f"Failed to import PPR C++ extension: {e}. " - "If the extension is not yet compiled, run `uv pip install -e gigl-core/` from the GiGL root. " - "If it is compiled, ensure `import torch` is called before importing this module " - "so that libtorch shared libraries are loaded into the process first." - ) from e - -__all__ = ["PPRForwardPushState"] diff --git a/gigl-core/src/gigl_core/ppr_forward_push.pyi b/gigl-core/src/gigl_core/ppr_forward_push.pyi deleted file mode 100644 index 9a3c78fea..000000000 --- a/gigl-core/src/gigl_core/ppr_forward_push.pyi +++ /dev/null @@ -1,22 +0,0 @@ -import torch - -class PPRForwardPushState: - def __init__( - self, - seed_nodes: torch.Tensor, - seed_node_type_id: int, - alpha: float, - requeue_threshold_factor: float, - node_type_to_edge_type_ids: list[list[int]], - edge_type_to_dst_ntype_id: list[int], - degree_tensors: list[torch.Tensor], - ) -> None: ... - def drain_queue(self) -> dict[int, torch.Tensor] | None: ... - def push_residuals( - self, - fetched_by_etype_id: dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]], - ) -> None: ... - def extract_top_k( - self, max_ppr_nodes: int - ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: ... - def get_nodes_drained_per_iteration(self) -> list[int]: ... diff --git a/gigl-core/src/gigl_core/py.typed b/gigl-core/src/gigl_core/py.typed deleted file mode 100644 index e69de29bb..000000000 From 1ff88c1b536f88daf30d0586a5011a520f96088c Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 22:17:32 +0000 Subject: [PATCH 095/148] restore files --- gigl-core/src/gigl_core/__init__.py | 11 ++++++++++ gigl-core/src/gigl_core/ppr_forward_push.pyi | 22 ++++++++++++++++++++ gigl-core/src/gigl_core/py.typed | 0 3 files changed, 33 insertions(+) create mode 100644 gigl-core/src/gigl_core/ppr_forward_push.pyi create mode 100644 gigl-core/src/gigl_core/py.typed diff --git a/gigl-core/src/gigl_core/__init__.py b/gigl-core/src/gigl_core/__init__.py index e69de29bb..7bf8c9987 100644 --- a/gigl-core/src/gigl_core/__init__.py +++ b/gigl-core/src/gigl_core/__init__.py @@ -0,0 +1,11 @@ +try: + from gigl_core.ppr_forward_push import PPRForwardPushState +except ImportError as e: + raise ImportError( + f"Failed to import PPR C++ extension: {e}. " + "If the extension is not yet compiled, run `uv pip install -e gigl-core/` from the GiGL root. " + "If it is compiled, ensure `import torch` is called before importing this module " + "so that libtorch shared libraries are loaded into the process first." + ) from e + +__all__ = ["PPRForwardPushState"] diff --git a/gigl-core/src/gigl_core/ppr_forward_push.pyi b/gigl-core/src/gigl_core/ppr_forward_push.pyi new file mode 100644 index 000000000..9a3c78fea --- /dev/null +++ b/gigl-core/src/gigl_core/ppr_forward_push.pyi @@ -0,0 +1,22 @@ +import torch + +class PPRForwardPushState: + def __init__( + self, + seed_nodes: torch.Tensor, + seed_node_type_id: int, + alpha: float, + requeue_threshold_factor: float, + node_type_to_edge_type_ids: list[list[int]], + edge_type_to_dst_ntype_id: list[int], + degree_tensors: list[torch.Tensor], + ) -> None: ... + def drain_queue(self) -> dict[int, torch.Tensor] | None: ... + def push_residuals( + self, + fetched_by_etype_id: dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]], + ) -> None: ... + def extract_top_k( + self, max_ppr_nodes: int + ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: ... + def get_nodes_drained_per_iteration(self) -> list[int]: ... diff --git a/gigl-core/src/gigl_core/py.typed b/gigl-core/src/gigl_core/py.typed new file mode 100644 index 000000000..e69de29bb From b0abe983b335dd51184b1ffde5d377a7539f7124 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 22:31:32 +0000 Subject: [PATCH 096/148] Fix --- pyproject.toml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e5da00a2e..8f36d93dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,9 +102,9 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", ] -# gigl-core uses torch from the ambient environment (no isolated build env). -# This matches how PyG's pyg_lib is built — torch is never on PyPI so build -# isolation would prevent finding it. +# gigl-core must build against torch, which is not on PyPI. An isolated build +# environment would fail to find it, so we disable isolation and let the build +# use the ambient environment where torch is already installed. no-build-isolation-package = ["gigl-core"] [dependency-groups] @@ -264,8 +264,6 @@ build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] include = ["gigl*", "snapchat*"] -exclude = ["gigl-core*", "tests*"] -namespaces = true [tool.setuptools.package-data] # Include dep_vars.env from the root directory From e015cda55023a75e744c25002ca39d659a42d4f4 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 22:38:36 +0000 Subject: [PATCH 097/148] remove cpp references --- gigl-core/CMakeLists.txt | 119 ++++++++++++++++++++------------- gigl-core/pyproject.toml | 9 ++- gigl-core/tests/CMakeLists.txt | 4 +- 3 files changed, 78 insertions(+), 54 deletions(-) diff --git a/gigl-core/CMakeLists.txt b/gigl-core/CMakeLists.txt index 83420f2b0..d4afbf690 100644 --- a/gigl-core/CMakeLists.txt +++ b/gigl-core/CMakeLists.txt @@ -6,15 +6,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # CMP0104: CMake 3.18+ warns when enable_language(CUDA) is called without -# CMAKE_CUDA_ARCHITECTURES being set. Set it to OFF — Torch provides a -# comprehensive arch list via TORCH_LIBRARIES. +# CMAKE_CUDA_ARCHITECTURES being set. Set it to OFF so CMake does not inject +# any -gencode flags (torch provides its own arch list via TORCH_LIBRARIES). cmake_policy(SET CMP0104 NEW) set(CMAKE_CUDA_ARCHITECTURES OFF) # Enable CUDA only when the toolkit is present; allows the same CMakeLists.txt -# to build on CPU-only machines without requiring nvcc. find_package(Torch) -# internally calls enable_language(CUDA) when torch was built with CUDA support, -# which requires CMAKE_CUDA_COMPILER to be set — hence the nvcc hint below. +# to build on CPU-only machines without requiring nvcc. include(CheckLanguage) check_language(CUDA) if(NOT CMAKE_CUDA_COMPILER) @@ -26,56 +24,83 @@ if(CMAKE_CUDA_COMPILER) set(CMAKE_CUDA_STANDARD_REQUIRED ON) endif() -find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) +# --------------------------------------------------------------------------- +# Extension modules — auto-discovered. +# Files named python_*.cpp under csrc/ are compiled as pybind11 extension +# modules. The companion .cpp (without the "python_" prefix) is included +# automatically when present. Add a new extension by dropping source files +# here; no changes to this CMakeLists.txt are needed. +# --------------------------------------------------------------------------- +if(CMAKE_CUDA_COMPILER) + file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/csrc/python_*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/csrc/python_*.cu" + ) +else() + file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/csrc/python_*.cpp" + ) +endif() + +if(_PYTHON_SRCS) + find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) + + # Locate pybind11 and torch cmake configs by scanning CMAKE_PREFIX_PATH, + # which scikit-build-core sets to the active environment's site-packages. + foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) + if(NOT pybind11_DIR AND EXISTS "${_prefix}/pybind11/share/cmake/pybind11") + set(pybind11_DIR "${_prefix}/pybind11/share/cmake/pybind11") + endif() + if(NOT TORCH_CMAKE_PREFIX AND EXISTS "${_prefix}/torch/share/cmake") + set(TORCH_CMAKE_PREFIX "${_prefix}/torch/share/cmake") + endif() + endforeach() -# Locate pybind11 and torch cmake configs by scanning CMAKE_PREFIX_PATH, which -# scikit-build-core sets to the active environment's site-packages directory. -foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) - if(NOT pybind11_DIR AND EXISTS "${_prefix}/pybind11/share/cmake/pybind11") - set(pybind11_DIR "${_prefix}/pybind11/share/cmake/pybind11") + if(NOT pybind11_DIR) + message(FATAL_ERROR "Cannot find pybind11 cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") endif() - if(NOT TORCH_CMAKE_PREFIX AND EXISTS "${_prefix}/torch/share/cmake") - set(TORCH_CMAKE_PREFIX "${_prefix}/torch/share/cmake") + if(NOT TORCH_CMAKE_PREFIX) + message(FATAL_ERROR "Cannot find torch cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") endif() -endforeach() -if(NOT pybind11_DIR) - message(FATAL_ERROR "Cannot find pybind11 cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") -endif() -if(NOT TORCH_CMAKE_PREFIX) - message(FATAL_ERROR "Cannot find torch cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") -endif() + find_package(pybind11 CONFIG REQUIRED) + find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") -find_package(pybind11 CONFIG REQUIRED) -find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") + # torch_python provides the pybind11 type casters for at::Tensor. It is not + # included in TORCH_LIBRARIES but is required for extensions that pass + # tensors across the Python/C++ boundary. + find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_INSTALL_PREFIX}/lib" REQUIRED) -# torch_python provides the pybind11 type casters for at::Tensor. It is not -# included in TORCH_LIBRARIES but is required for extensions that pass tensors -# across the Python/C++ boundary. -find_library(TORCH_PYTHON_LIBRARY torch_python PATHS "${TORCH_INSTALL_PREFIX}/lib" REQUIRED) + set(GIGL_COMPILE_FLAGS -O3 -g -Wall -Wextra -Wno-unused-parameter) + # nvcc does not accept bare -Wall/-Wextra; wrap with -Xcompiler for CUDA. + set(GIGL_COMPILE_FLAGS_CUDA -O3 -Xcompiler=-g,-Wall,-Wextra,-Wno-unused-parameter) -set(GIGL_COMPILE_FLAGS -O3 -g -Wall -Wextra -Wno-unused-parameter) -# nvcc does not accept bare -Wall/-Wextra; wrap with -Xcompiler for CUDA sources. -set(GIGL_COMPILE_FLAGS_CUDA -O3 -Xcompiler=-g,-Wall,-Wextra,-Wno-unused-parameter) + foreach(_py_src IN LISTS _PYTHON_SRCS) + get_filename_component(_dir "${_py_src}" DIRECTORY) + get_filename_component(_stem "${_py_src}" NAME_WE) + string(REGEX REPLACE "^python_" "" _name "${_stem}") -# --------------------------------------------------------------------------- -# ppr_forward_push extension module -# --------------------------------------------------------------------------- -pybind11_add_module(ppr_forward_push - csrc/sampling/python_ppr_forward_push.cpp - csrc/sampling/ppr_forward_push.cpp -) -target_link_libraries(ppr_forward_push PRIVATE "${TORCH_LIBRARIES}" "${TORCH_PYTHON_LIBRARY}") -target_compile_options(ppr_forward_push PRIVATE - $<$:${GIGL_COMPILE_FLAGS}> - $<$:${GIGL_COMPILE_FLAGS_CUDA}> -) -# TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. -# PyTorch's own build system sets this; we must define it explicitly here. -target_compile_definitions(ppr_forward_push PRIVATE TORCH_EXTENSION_NAME=ppr_forward_push) -# Install into the gigl_core/ subdirectory so the .so is importable as -# gigl_core.ppr_forward_push after editable install. -install(TARGETS ppr_forward_push DESTINATION gigl_core) + set(_sources "${_py_src}") + if(EXISTS "${_dir}/${_name}.cpp") + list(APPEND _sources "${_dir}/${_name}.cpp") + endif() + if(CMAKE_CUDA_COMPILER AND EXISTS "${_dir}/${_name}.cu") + list(APPEND _sources "${_dir}/${_name}.cu") + endif() + + pybind11_add_module("${_name}" ${_sources}) + target_link_libraries("${_name}" PRIVATE "${TORCH_LIBRARIES}" "${TORCH_PYTHON_LIBRARY}") + target_compile_options("${_name}" PRIVATE + $<$:${GIGL_COMPILE_FLAGS}> + $<$:${GIGL_COMPILE_FLAGS_CUDA}> + ) + # TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. + # PyTorch's own build system sets this; we must define it explicitly here. + target_compile_definitions("${_name}" PRIVATE "TORCH_EXTENSION_NAME=${_name}") + # Install into gigl_core/ so the .so is importable as gigl_core.. + install(TARGETS "${_name}" DESTINATION gigl_core) + endforeach() +endif() option(GIGL_CORE_BUILD_TESTS "Build C++ unit tests (used by make unit_test_cpp)" OFF) if(GIGL_CORE_BUILD_TESTS) diff --git a/gigl-core/pyproject.toml b/gigl-core/pyproject.toml index 2a63687df..8fc595572 100644 --- a/gigl-core/pyproject.toml +++ b/gigl-core/pyproject.toml @@ -18,11 +18,10 @@ build-backend = "scikit_build_core.build" [tool.scikit-build] cmake.version = ">=3.18" build-dir = ".cache/cmake_build" -# Default editable mode is `redirect`: scikit-build-core writes the compiled .so -# into .cache/cmake_build/ and installs an import-hook shim into site-packages -# that resolves gigl_core.ppr_forward_push to that path. `editable.rebuild` -# stays off so imports never block on CMake — explicit `uv pip install -e gigl-core/` -# drives rebuilds. +# Default editable mode is `redirect`: scikit-build-core writes compiled .so +# files into .cache/cmake_build/ and installs an import-hook shim into +# site-packages that resolves them. `editable.rebuild` stays off so imports +# never block on CMake — explicit `uv pip install -e gigl-core/` drives rebuilds. editable.rebuild = false [tool.uv] diff --git a/gigl-core/tests/CMakeLists.txt b/gigl-core/tests/CMakeLists.txt index 10b9520cf..a1638e767 100644 --- a/gigl-core/tests/CMakeLists.txt +++ b/gigl-core/tests/CMakeLists.txt @@ -39,8 +39,8 @@ endif() foreach(test_source ${TEST_SOURCES}) # Derive a unique binary name from the path relative to this directory, e.g.: - # ppr_forward_push_test.cpp → ppr_forward_push_test - # sampling/ppr_forward_push_test.cpp → sampling_ppr_forward_push_test + # foo_test.cpp → foo_test + # sampling/foo_test.cpp → sampling_foo_test file(RELATIVE_PATH _rel "${CMAKE_CURRENT_SOURCE_DIR}" "${test_source}") string(REPLACE "/" "_" test_name "${_rel}") string(REGEX REPLACE "\\.[^.]+$" "" test_name "${test_name}") From b7782de9941d58fa94481edfa16ba3dd9b7df004 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 22:55:12 +0000 Subject: [PATCH 098/148] small fixes --- .clang-format | 13 +++++++------ .clang-tidy | 2 +- .github/workflows/on-pr-merge.yml | 1 + docs/cpp_style_guide.md | 16 ++++++++-------- gigl-core/tests/CMakeLists.txt | 2 +- scripts/run_cpp_lint.py | 5 ++++- 6 files changed, 22 insertions(+), 17 deletions(-) diff --git a/.clang-format b/.clang-format index fccba9f02..9937b0283 100644 --- a/.clang-format +++ b/.clang-format @@ -35,15 +35,16 @@ DisableFormat: false FixNamespaceComments: true ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] # Lower Priority numbers sort first (Priority 1 appears before Priority 2, etc.). -# This is the Google/PyTorch convention — the opposite of the LLVM default. -# Result: project-local headers (1) → torch/pybind11 (2) → system/third-party (3). -# Add graphlearn_torch to the Priority 2 regex when GLT headers appear in the codebase. +# List order matches priority order (1 → 2 → 3); torch/pybind11 must be listed before the +# broader '^<' rule so it is matched first. +# Result: torch/pybind11 (1) → system/third-party (2) → project-local headers (3). +# Add graphlearn_torch to the Priority 1 regex when GLT headers appear in the codebase. IncludeCategories: - - Regex: '.*' - Priority: 1 - Regex: '^<(torch|pybind11)/' - Priority: 2 + Priority: 1 - Regex: '^(<|"gtest/)' + Priority: 2 + - Regex: '.*' Priority: 3 IncludeIsMainRegex: '^$' IndentCaseLabels: true diff --git a/.clang-tidy b/.clang-tidy index 8169ebed3..5dd99dd83 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -50,7 +50,7 @@ Checks: > # dropped. Only diagnostics in our own headers (.*/gigl/csrc/.*) are reported, # and those are treated as hard errors. WarningsAsErrors: '*' -HeaderFilterRegex: '.*/gigl/csrc/.*' +HeaderFilterRegex: '.*/gigl-core/csrc/.*' FormatStyle: none # CheckOptions: per-check tuning parameters. Each entry configures a specific # option for an individual check, using the form: diff --git a/.github/workflows/on-pr-merge.yml b/.github/workflows/on-pr-merge.yml index 68ce947f9..81f9f37d8 100644 --- a/.github/workflows/on-pr-merge.yml +++ b/.github/workflows/on-pr-merge.yml @@ -73,6 +73,7 @@ jobs: ci-unit-test-cpp: if: github.event_name == 'merge_group' runs-on: ubuntu-latest + timeout-minutes: 20 steps: - uses: actions/checkout@v4 - name: Install C++ dependencies diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index d0d190411..ce3a6f71e 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -81,15 +81,15 @@ header. ### Include ordering -Includes are sorted and split into three priority groups: +Includes are sorted and split into three priority groups (lower number = appears first in the file): -| Priority | Pattern | Group | -| -------- | ---------------------- | ------------------------------------------- | -| 1 | `.*` | Local project headers (first) | -| 2 | `^<(torch\|pybind11)/` | Torch and pybind11 headers | -| 3 | `^(<\|"gtest/)` | System and other third-party headers (last) | +| Priority | Pattern | Group | +| -------- | ---------------------- | -------------------------------------------- | +| 1 | `^<(torch\|pybind11)/` | Torch and pybind11 headers (first) | +| 2 | `^(<\|"gtest/)` | System and other third-party headers | +| 3 | `.*` | Local project headers (last) | -> When GLT (`graphlearn_torch`) headers are added, include `graphlearn_torch` in the Priority 2 pattern. +> When GLT (`graphlearn_torch`) headers are added, include `graphlearn_torch` in the Priority 1 pattern. ### Raw string formatting @@ -163,7 +163,7 @@ Enforced via `readability-identifier-naming`: | Option | Value | Effect | | ---------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | -| `HeaderFilterRegex` | `.*/gigl/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | +| `HeaderFilterRegex` | `.*/gigl-core/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | | `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | | `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | | `modernize-loop-convert.NamingStyle` | `camelBack` | Auto-generated loop variable names use camelBack, matching `readability-identifier-naming.VariableCase` | diff --git a/gigl-core/tests/CMakeLists.txt b/gigl-core/tests/CMakeLists.txt index a1638e767..74eac1f40 100644 --- a/gigl-core/tests/CMakeLists.txt +++ b/gigl-core/tests/CMakeLists.txt @@ -13,7 +13,7 @@ include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.14.0 + GIT_TAG 58d77fa8070e8cec2dc1ed015d66b454c8d78850 # v1.14.0 GIT_SHALLOW TRUE ) # Prevent GoogleTest from overriding the compiler's runtime on Windows diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 6b501a1b6..2009e285d 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -62,7 +62,10 @@ def main() -> None: futures = {executor.submit(_check_file, s): s for s in sources} for future in as_completed(futures): source = futures[future] - diagnostics = future.result() + try: + diagnostics = future.result() + except Exception as exc: + diagnostics = [f"linter error: {exc}"] if diagnostics: failures[source] = diagnostics From 57c6df320a838d6dc89085ee86c2d421c09ba88f Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 23:15:21 +0000 Subject: [PATCH 099/148] Update release --- .github/workflows/release.yml | 29 ++++++++-- RELEASING.md | 55 +++++++++++++++++++ .../getting_started/installation.md | 32 ++++++----- pyproject.toml | 4 +- 4 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 RELEASING.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dbe427863..797de512a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,11 @@ on: # - building and releasing docker images # - building and releasing KFP pipeline workflow_dispatch: + inputs: + release_gigl_core: + description: "Release gigl-core wheel (only needed when C++ code changed)" + type: boolean + default: false permissions: contents: read @@ -55,10 +60,26 @@ jobs: # Pre-install keyring and Artifact Registry plugin from the public PyPI uv tool install keyring --with keyrings.google-artifactregistry-auth==1.1.2 - - name: Build Whl Distribution - run: uv build --wheel + # gigl is pure Python — build is fast and produces the same wheel on both + # runners. Publish to each variant's registry so the registry is + # self-contained: a user only needs one GCP extra-index URL per variant. + - name: Build and publish gigl wheel + run: | + uv build --wheel + uv publish --index ${{ matrix.index-name }} --username oauth2accesstoken --keyring-provider subprocess + + # gigl-core contains compiled C++/CUDA extensions that are ABI-bound to the + # torch variant. Build and publish one wheel per variant. + # --no-build-isolation: torch is not on PyPI; the build must use the ambient + # environment where torch is already installed by make install_dev_deps. + # Only runs when release_gigl_core=true (i.e. when C++ code changed). + - name: Build gigl-core wheel + if: ${{ inputs.release_gigl_core }} + working-directory: gigl-core + run: uv build --wheel --no-build-isolation - - name: Publish Package 🚀 - # We upload the build whls to Google Artifact Registry. + - name: Publish gigl-core wheel + if: ${{ inputs.release_gigl_core }} + working-directory: gigl-core run: | uv publish --index ${{ matrix.index-name }} --username oauth2accesstoken --keyring-provider subprocess diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 000000000..4af32bb7c --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,55 @@ +# Releasing GiGL + +## Two-wheel model + +GiGL is distributed as two wheels that are always installed together: + +- **`gigl`** — pure Python (same wheel for CPU and CUDA users) +- **`gigl-core`** — compiled C++/CUDA extensions, ABI-bound to the torch variant + +Each has its own version. `gigl-core` is versioned **independently** — it only needs a new release when C++ code under `gigl-core/` actually changes. `gigl` pins an exact `gigl-core` version in its `pyproject.toml`; that pin is updated in the same PR as any C++ change. + +## How to trigger a release + +Releases are triggered manually via the **Release GiGL** GitHub Actions workflow (`release.yml`): + +1. Go to the **Actions** tab in the GitHub repository. +2. Select **Release GiGL** from the left sidebar. +3. Click **Run workflow** (top right of the workflow runs table). +4. A form appears with one input: + - **Release gigl-core wheel** — check this only if C++ code changed (see below). +5. Click **Run workflow** to start. + +The workflow runs two jobs in parallel — one on a CPU runner, one on a GPU runner — and publishes to both variant registries. + +## Releasing gigl (Python-only change) + +Use this when no files under `gigl-core/` were modified. + +1. Bump the version in `gigl/pyproject.toml` (`version = "X.Y.Z"`). +2. Open a PR, get it merged to `main`. +3. Trigger the **Release GiGL** workflow with **Release gigl-core wheel** unchecked. + +Both the CPU and CUDA `gigl` wheels are built and published. The existing `gigl-core` wheel in the registry continues to satisfy the pinned dependency — no `gigl-core` action needed. + +## Releasing gigl-core (C++ changed) + +Use this when files under `gigl-core/csrc/` or `gigl-core/CMakeLists.txt` were modified. + +1. Bump the version in `gigl-core/pyproject.toml` (`version = "X.Y.Z"`). +2. Update the matching pin in `gigl/pyproject.toml`: `"gigl-core==X.Y.Z"`. +3. Open a PR with both version changes, get it merged to `main`. +4. Trigger the **Release GiGL** workflow with **Release gigl-core wheel** checked. + +This publishes new `gigl-core` wheels (cpu + cu128) **and** new `gigl` wheels (which carry the updated pin). + +## What gets published + +Each release run publishes to two self-contained registries: + +| Registry | Packages | +| -------- | -------- | +| `gcp-release-registry-cpu` | `gigl` (pure Python) + `gigl-core` (CPU wheel, if releasing) | +| `gcp-release-registry-cu128` | `gigl` (pure Python) + `gigl-core` (CUDA 12.8 wheel, if releasing) | + +Users install from exactly one registry based on their variant — see [installation docs](docs/user_guide/getting_started/installation.md). diff --git a/docs/user_guide/getting_started/installation.md b/docs/user_guide/getting_started/installation.md index ef940db79..a014ebfd1 100644 --- a/docs/user_guide/getting_started/installation.md +++ b/docs/user_guide/getting_started/installation.md @@ -10,10 +10,20 @@ These are the current environments supported by GiGL ## Available Versions -You can see the available wheels for GiGL: +GiGL is distributed as two wheels that are installed together: -- [CPU wheels](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl?project=external-snap-ci-github-gigl) -- [CUDA wheels](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl-cu128?project=external-snap-ci-github-gigl) +- **`gigl`** — pure Python package (same wheel for CPU and CUDA users) +- **`gigl-core`** — compiled C++/CUDA extensions, ABI-bound to the torch variant + +You do not need to install `gigl-core` directly; it is a dependency of `gigl` and is +resolved automatically from the same registry. + +Each registry is self-contained — you only need one GCP extra-index URL: + +| Variant | Registry | +| ------- | -------- | +| CPU | [gigl (CPU registry)](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl?project=external-snap-ci-github-gigl) | +| CUDA 12.8 | [gigl-cu128 (CUDA registry)](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl-cu128?project=external-snap-ci-github-gigl) | ## Install Prerequisites - setting up your dev machine @@ -105,31 +115,27 @@ Below we provide two ways to bootstrap an environment for using and/or developin 2. Install GiGL -#### Install GiGL + necessary tooling for PyG 2.7 + Torch 2.8 on Cuda12.8 +#### Install GiGL + necessary tooling for PyG 2.7 + Torch 2.8 on CUDA 12.8 ```bash -pip install "gigl[pyg27-torch28-cu128, transform]==0.1.0" \ +pip install "gigl[pyg27-torch28-cu128, transform]==0.2.0" \ --extra-index-url=https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl-cu128/simple/ \ --extra-index-url=https://download.pytorch.org/whl/cu128 \ --extra-index-url=https://data.pyg.org/whl/torch-2.8.0+cu128.html ``` -Currently, building/using wheels for GLT is error prone, thus we opt to install from source every time. Run post-install -script to setup GLT dependency: - -```bash -gigl-post-install -``` - #### Install GiGL + necessary tooling for PyG 2.7 + Torch 2.8 on CPU ```bash -pip install "gigl[pyg27-torch28-cpu, transform]==0.1.0" \ +pip install "gigl[pyg27-torch28-cpu, transform]==0.2.0" \ --extra-index-url=https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl/simple/ \ --extra-index-url=https://download.pytorch.org/whl/cpu \ --extra-index-url=https://data.pyg.org/whl/torch-2.8.0+cpu.html ``` +pip resolves and installs `gigl-core` automatically from the same GCP registry. +No separate install step is needed. + Currently, building/using wheels for GLT is error prone, thus we opt to install from source every time. Run post-install script to setup GLT dependency: diff --git a/pyproject.toml b/pyproject.toml index 8f36d93dc..e970df498 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,8 +14,8 @@ dependencies = [ "argo-workflows", "chardet", # gigl-core hosts all C++ / CUDA / pybind11 extensions. Separate wheel per torch - # variant (cpu/cu128). Same pattern PyG uses for pyg_lib. - "gigl-core", + # variant (cpu/cu128). Version must match gigl exactly. + "gigl-core==0.2.0", "google-cloud-aiplatform", "google-cloud-dataproc", "google-cloud-logging", From 65d1788fea00b7ea74385c756c14662cfe4c66be Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 23:25:26 +0000 Subject: [PATCH 100/148] Update --- containers/Dockerfile.cpu.base | 5 +++++ containers/Dockerfile.cuda.base | 5 +++++ containers/Dockerfile.dataflow.base | 5 +++++ requirements/install_py_deps.sh | 13 ++++++------- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/containers/Dockerfile.cpu.base b/containers/Dockerfile.cpu.base index 4ef552789..ea3110390 100644 --- a/containers/Dockerfile.cpu.base +++ b/containers/Dockerfile.cpu.base @@ -26,6 +26,11 @@ COPY uv.lock uv.lock COPY requirements requirements COPY gigl/scripts gigl/scripts COPY .python-version .python-version +# gigl-core is a path dependency in pyproject.toml. uv sync needs its metadata to +# resolve the lockfile. Copying only the build manifest (no C++ sources) so cmake +# configures but compiles nothing — the src Dockerfile installs the real wheel later. +COPY gigl-core/pyproject.toml gigl-core/pyproject.toml +COPY gigl-core/CMakeLists.txt gigl-core/CMakeLists.txt RUN bash ./requirements/install_py_deps.sh diff --git a/containers/Dockerfile.cuda.base b/containers/Dockerfile.cuda.base index fdca2c01b..65ccebe53 100644 --- a/containers/Dockerfile.cuda.base +++ b/containers/Dockerfile.cuda.base @@ -31,6 +31,11 @@ COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock COPY requirements requirements COPY gigl/scripts gigl/scripts +# gigl-core is a path dependency in pyproject.toml. uv sync needs its metadata to +# resolve the lockfile. Copying only the build manifest (no C++ sources) so cmake +# configures but compiles nothing — the src Dockerfile installs the real wheel later. +COPY gigl-core/pyproject.toml gigl-core/pyproject.toml +COPY gigl-core/CMakeLists.txt gigl-core/CMakeLists.txt RUN bash ./requirements/install_py_deps.sh diff --git a/containers/Dockerfile.dataflow.base b/containers/Dockerfile.dataflow.base index 76a57d14d..21611d884 100644 --- a/containers/Dockerfile.dataflow.base +++ b/containers/Dockerfile.dataflow.base @@ -25,6 +25,11 @@ COPY pyproject.toml pyproject.toml COPY uv.lock uv.lock COPY requirements requirements COPY gigl/scripts gigl/scripts +# gigl-core is a path dependency in pyproject.toml. uv sync needs its metadata to +# resolve the lockfile. Copying only the build manifest (no C++ sources) so cmake +# configures but compiles nothing — the src Dockerfile installs the real wheel later. +COPY gigl-core/pyproject.toml gigl-core/pyproject.toml +COPY gigl-core/CMakeLists.txt gigl-core/CMakeLists.txt RUN bash ./requirements/install_py_deps.sh --skip-glt-post-install diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index 3cdafc9c0..d3e1cbdaa 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -138,13 +138,12 @@ install_gigl_lib_deps() { flag_use_inexact_match="--inexact" fi - # --no-install-project: skip building and installing the workspace members (gigl, - # gigl-core) here. They are installed separately: - # - gigl (pure Python): `uv pip install .` in *.src Dockerfiles - # - gigl-core (C++ extension): `uv pip install gigl-core/` in *.src Dockerfiles - # Base Docker images only copy pyproject.toml + uv.lock, not gigl-core/. Without - # this flag, uv sync would try to build gigl-core's C++ extension and fail because - # the source tree is absent. + # --no-install-project: skip building and installing the root gigl package here. + # gigl (pure Python) is installed separately via `uv pip install .` in *.src Dockerfiles. + # gigl-core (C++ extensions) is a path dependency — it IS installed here from the stub + # files (pyproject.toml + CMakeLists.txt) copied into the base image. With no C++ sources + # present, cmake configures but compiles nothing, producing an empty wheel. + # The *.src Dockerfiles copy the full gigl-core source and reinstall the real wheel. if [[ $DEV -eq 1 ]] then # https://docs.astral.sh/uv/reference/cli/#uv-sync From 45cd03afade2bf0dbb66edffaa33ac3e73b3c44e Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 24 Apr 2026 23:39:31 +0000 Subject: [PATCH 101/148] Update release todo and copy readme in dockerfiles --- .github/workflows/release.yml | 5 ----- containers/Dockerfile.cpu.base | 1 + containers/Dockerfile.cuda.base | 1 + containers/Dockerfile.dataflow.base | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 797de512a..ed77a1a5f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,5 @@ name: Release GiGL -# TODO: Before the first release using this workflow, complete the following one-time GCP setup: -# 1. Create the `gigl-cu128` Artifact Registry Python repository in GCP project -# `external-snap-ci-github-gigl` (the CPU registry `gigl` already exists). -# 2. Grant the release service account write access to the new `gigl-cu128` repository. - on: # Triggers the workflow manually for now until we have full support for releasing: # - building and releasing docker images diff --git a/containers/Dockerfile.cpu.base b/containers/Dockerfile.cpu.base index ea3110390..cba87627f 100644 --- a/containers/Dockerfile.cpu.base +++ b/containers/Dockerfile.cpu.base @@ -31,6 +31,7 @@ COPY .python-version .python-version # configures but compiles nothing — the src Dockerfile installs the real wheel later. COPY gigl-core/pyproject.toml gigl-core/pyproject.toml COPY gigl-core/CMakeLists.txt gigl-core/CMakeLists.txt +COPY gigl-core/README.md gigl-core/README.md RUN bash ./requirements/install_py_deps.sh diff --git a/containers/Dockerfile.cuda.base b/containers/Dockerfile.cuda.base index 65ccebe53..f6d05397f 100644 --- a/containers/Dockerfile.cuda.base +++ b/containers/Dockerfile.cuda.base @@ -36,6 +36,7 @@ COPY gigl/scripts gigl/scripts # configures but compiles nothing — the src Dockerfile installs the real wheel later. COPY gigl-core/pyproject.toml gigl-core/pyproject.toml COPY gigl-core/CMakeLists.txt gigl-core/CMakeLists.txt +COPY gigl-core/README.md gigl-core/README.md RUN bash ./requirements/install_py_deps.sh diff --git a/containers/Dockerfile.dataflow.base b/containers/Dockerfile.dataflow.base index 21611d884..7eb98df8d 100644 --- a/containers/Dockerfile.dataflow.base +++ b/containers/Dockerfile.dataflow.base @@ -30,6 +30,7 @@ COPY gigl/scripts gigl/scripts # configures but compiles nothing — the src Dockerfile installs the real wheel later. COPY gigl-core/pyproject.toml gigl-core/pyproject.toml COPY gigl-core/CMakeLists.txt gigl-core/CMakeLists.txt +COPY gigl-core/README.md gigl-core/README.md RUN bash ./requirements/install_py_deps.sh --skip-glt-post-install From 308fd672e80333c9196a72efb86e6f07b2b16192 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sat, 25 Apr 2026 00:00:26 +0000 Subject: [PATCH 102/148] update builder dockerfile --- containers/Dockerfile.builder | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/containers/Dockerfile.builder b/containers/Dockerfile.builder index b228fc263..6388a5c6b 100644 --- a/containers/Dockerfile.builder +++ b/containers/Dockerfile.builder @@ -62,6 +62,12 @@ COPY gigl/scripts gigl/scripts COPY .python-version tmp/.python-version +# gigl-core is a path dependency in pyproject.toml. uv sync needs its metadata to +# resolve the lockfile. Copying only the build manifest (no C++ sources) so cmake +# configures but compiles nothing — the src Dockerfile installs the real wheel later. +COPY gigl-core/pyproject.toml gigl-core/pyproject.toml +COPY gigl-core/CMakeLists.txt gigl-core/CMakeLists.txt +COPY gigl-core/README.md gigl-core/README.md RUN bash ./requirements/install_py_deps.sh --dev # The UV_PROJECT_ENVIRONMENT environment variable can be used to configure the project virtual environment path From c95a4269d10746c331fcf48d89b66aa874de179f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Apr 2026 00:10:37 +0000 Subject: [PATCH 103/148] [AUTOMATED] Update dep.vars, and other relevant files with new image names --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- gigl/dep_vars.env | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index d0e407f02..263d8cace 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 entrypoint: /bin/bash args: - -c diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index 85ef4d21b..a458e2b48 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:b34c863a2168c8df5a6da1f6385e5d374f0175d2.91.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 From 50acb283c72c2c2e3b2e7cd3d4c3b8579ccd4496 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sat, 25 Apr 2026 00:50:34 +0000 Subject: [PATCH 104/148] Format md --- RELEASING.md | 19 +++++++++----- docs/cpp_style_guide.md | 26 +++++++++---------- .../getting_started/installation.md | 13 +++++----- gigl-core/README.md | 4 +-- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 4af32bb7c..88c2e2ee6 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -7,7 +7,9 @@ GiGL is distributed as two wheels that are always installed together: - **`gigl`** — pure Python (same wheel for CPU and CUDA users) - **`gigl-core`** — compiled C++/CUDA extensions, ABI-bound to the torch variant -Each has its own version. `gigl-core` is versioned **independently** — it only needs a new release when C++ code under `gigl-core/` actually changes. `gigl` pins an exact `gigl-core` version in its `pyproject.toml`; that pin is updated in the same PR as any C++ change. +Each has its own version. `gigl-core` is versioned **independently** — it only needs a new release when C++ code under +`gigl-core/` actually changes. `gigl` pins an exact `gigl-core` version in its `pyproject.toml`; that pin is updated in +the same PR as any C++ change. ## How to trigger a release @@ -20,7 +22,8 @@ Releases are triggered manually via the **Release GiGL** GitHub Actions workflow - **Release gigl-core wheel** — check this only if C++ code changed (see below). 5. Click **Run workflow** to start. -The workflow runs two jobs in parallel — one on a CPU runner, one on a GPU runner — and publishes to both variant registries. +The workflow runs two jobs in parallel — one on a CPU runner, one on a GPU runner — and publishes to both variant +registries. ## Releasing gigl (Python-only change) @@ -30,7 +33,8 @@ Use this when no files under `gigl-core/` were modified. 2. Open a PR, get it merged to `main`. 3. Trigger the **Release GiGL** workflow with **Release gigl-core wheel** unchecked. -Both the CPU and CUDA `gigl` wheels are built and published. The existing `gigl-core` wheel in the registry continues to satisfy the pinned dependency — no `gigl-core` action needed. +Both the CPU and CUDA `gigl` wheels are built and published. The existing `gigl-core` wheel in the registry continues to +satisfy the pinned dependency — no `gigl-core` action needed. ## Releasing gigl-core (C++ changed) @@ -47,9 +51,10 @@ This publishes new `gigl-core` wheels (cpu + cu128) **and** new `gigl` wheels (w Each release run publishes to two self-contained registries: -| Registry | Packages | -| -------- | -------- | -| `gcp-release-registry-cpu` | `gigl` (pure Python) + `gigl-core` (CPU wheel, if releasing) | +| Registry | Packages | +| ---------------------------- | ------------------------------------------------------------------ | +| `gcp-release-registry-cpu` | `gigl` (pure Python) + `gigl-core` (CPU wheel, if releasing) | | `gcp-release-registry-cu128` | `gigl` (pure Python) + `gigl-core` (CUDA 12.8 wheel, if releasing) | -Users install from exactly one registry based on their variant — see [installation docs](docs/user_guide/getting_started/installation.md). +Users install from exactly one registry based on their variant — see +[installation docs](docs/user_guide/getting_started/installation.md). diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index ce3a6f71e..4e0aff48a 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -83,11 +83,11 @@ header. Includes are sorted and split into three priority groups (lower number = appears first in the file): -| Priority | Pattern | Group | -| -------- | ---------------------- | -------------------------------------------- | -| 1 | `^<(torch\|pybind11)/` | Torch and pybind11 headers (first) | -| 2 | `^(<\|"gtest/)` | System and other third-party headers | -| 3 | `.*` | Local project headers (last) | +| Priority | Pattern | Group | +| -------- | ---------------------- | ------------------------------------ | +| 1 | `^<(torch\|pybind11)/` | Torch and pybind11 headers (first) | +| 2 | `^(<\|"gtest/)` | System and other third-party headers | +| 3 | `.*` | Local project headers (last) | > When GLT (`graphlearn_torch`) headers are added, include `graphlearn_torch` in the Priority 1 pattern. @@ -160,15 +160,15 @@ Enforced via `readability-identifier-naming`: ### Key option tuning -| Option | Value | Effect | -| ---------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | +| Option | Value | Effect | +| ---------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | | `HeaderFilterRegex` | `.*/gigl-core/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | -| `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | -| `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | -| `modernize-loop-convert.NamingStyle` | `camelBack` | Auto-generated loop variable names use camelBack, matching `readability-identifier-naming.VariableCase` | -| `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | -| `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | +| `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | +| `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | +| `modernize-loop-convert.NamingStyle` | `camelBack` | Auto-generated loop variable names use camelBack, matching `readability-identifier-naming.VariableCase` | +| `readability-function-size.LineThreshold` | `1000` | Functions over 1000 lines are flagged | +| `readability-braces-around-statements.ShortStatementLines` | `0` | Braces required for all control-flow bodies, even single-line | ______________________________________________________________________ diff --git a/docs/user_guide/getting_started/installation.md b/docs/user_guide/getting_started/installation.md index a014ebfd1..9955193c1 100644 --- a/docs/user_guide/getting_started/installation.md +++ b/docs/user_guide/getting_started/installation.md @@ -15,14 +15,14 @@ GiGL is distributed as two wheels that are installed together: - **`gigl`** — pure Python package (same wheel for CPU and CUDA users) - **`gigl-core`** — compiled C++/CUDA extensions, ABI-bound to the torch variant -You do not need to install `gigl-core` directly; it is a dependency of `gigl` and is -resolved automatically from the same registry. +You do not need to install `gigl-core` directly; it is a dependency of `gigl` and is resolved automatically from the +same registry. Each registry is self-contained — you only need one GCP extra-index URL: -| Variant | Registry | -| ------- | -------- | -| CPU | [gigl (CPU registry)](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl?project=external-snap-ci-github-gigl) | +| Variant | Registry | +| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| CPU | [gigl (CPU registry)](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl?project=external-snap-ci-github-gigl) | | CUDA 12.8 | [gigl-cu128 (CUDA registry)](https://console.cloud.google.com/artifacts/python/external-snap-ci-github-gigl/us-central1/gigl/gigl-cu128?project=external-snap-ci-github-gigl) | ## Install Prerequisites - setting up your dev machine @@ -133,8 +133,7 @@ pip install "gigl[pyg27-torch28-cpu, transform]==0.2.0" \ --extra-index-url=https://data.pyg.org/whl/torch-2.8.0+cpu.html ``` -pip resolves and installs `gigl-core` automatically from the same GCP registry. -No separate install step is needed. +pip resolves and installs `gigl-core` automatically from the same GCP registry. No separate install step is needed. Currently, building/using wheels for GLT is error prone, thus we opt to install from source every time. Run post-install script to setup GLT dependency: diff --git a/gigl-core/README.md b/gigl-core/README.md index 7ff32c88e..c02f9301e 100644 --- a/gigl-core/README.md +++ b/gigl-core/README.md @@ -2,8 +2,8 @@ C++/CUDA pybind11 extension modules for [GiGL](https://github.com/snapchat/gigl). -This package contains the compiled native extensions. It is a workspace member of the -main `gigl` package and is built separately via scikit-build-core. +This package contains the compiled native extensions. It is a workspace member of the main `gigl` package and is built +separately via scikit-build-core. ## Building From 64d2c20cd626cb2d0a56a5937f38c430ca7ab4e5 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sat, 25 Apr 2026 00:52:55 +0000 Subject: [PATCH 105/148] fix dockerfile --- containers/Dockerfile.src | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/containers/Dockerfile.src b/containers/Dockerfile.src index c43de4c9a..4d77c6325 100644 --- a/containers/Dockerfile.src +++ b/containers/Dockerfile.src @@ -15,10 +15,10 @@ COPY snapchat snapchat COPY tests tests COPY examples examples -# Install gigl (pure Python — fast, no CMake). -RUN uv pip install . - -# Build and install gigl-core C++ extensions. gigl-core/ must be present -# for scikit-build-core to run CMake and link against torch. +# Build and install gigl-core C++ extensions first. gigl-core/ must be present +# before `uv pip install .` because gigl declares it as a path dependency. COPY gigl-core gigl-core RUN uv pip install gigl-core/ + +# Install gigl (pure Python — fast, no CMake). gigl-core is already satisfied above. +RUN uv pip install . From 36d0dbbb0b079a1d70b65c15a99fc4cc218bdff8 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sat, 25 Apr 2026 01:16:54 +0000 Subject: [PATCH 106/148] update dataflow dockerfile --- containers/Dockerfile.dataflow.src | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/containers/Dockerfile.dataflow.src b/containers/Dockerfile.dataflow.src index b5d29c7f0..d9b9c6ac7 100644 --- a/containers/Dockerfile.dataflow.src +++ b/containers/Dockerfile.dataflow.src @@ -13,6 +13,12 @@ COPY deployment deployment COPY gigl gigl COPY snapchat snapchat COPY tests tests + +# Build and install gigl-core C++ extensions first. gigl-core/ must be present +# before `uv pip install` because gigl declares it as a path dependency. +COPY gigl-core gigl-core +RUN uv pip install gigl-core/ + RUN uv pip install -e . WORKDIR / From 2611c5871ad52e41d38ae5bb2d046589ac760efb Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sun, 26 Apr 2026 18:53:10 +0000 Subject: [PATCH 107/148] Update release to have cmake --- .github/workflows/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed77a1a5f..8c816be4e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Install cmake + run: sudo apt-get install -y cmake + - name: Setup Python deps and gcloud uses: ./.github/actions/setup-python-tools with: From e79980632dfd104cec20e705f93785b8315714aa Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sun, 26 Apr 2026 19:14:27 +0000 Subject: [PATCH 108/148] Use explicit publish-url in release workflow instead of named index --- .github/workflows/release.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c816be4e..8b1cc52e2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,9 +25,11 @@ jobs: - runner: ubuntu-latest torch-variant: cpu index-name: gcp-release-registry-cpu + publish-url: https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl - runner: gigl-gpu-instances torch-variant: cu128 index-name: gcp-release-registry-cu128 + publish-url: https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl-cu128 env: PROJECT_ID: ${{ vars.GCP_PROJECT_ID }} environment: @@ -64,7 +66,7 @@ jobs: - name: Build and publish gigl wheel run: | uv build --wheel - uv publish --index ${{ matrix.index-name }} --username oauth2accesstoken --keyring-provider subprocess + uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess # gigl-core contains compiled C++/CUDA extensions that are ABI-bound to the # torch variant. Build and publish one wheel per variant. @@ -80,4 +82,4 @@ jobs: if: ${{ inputs.release_gigl_core }} working-directory: gigl-core run: | - uv publish --index ${{ matrix.index-name }} --username oauth2accesstoken --keyring-provider subprocess + uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess From 496abda97c0ee96432b43b149d3e2aae89c8b067 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sun, 26 Apr 2026 19:15:10 +0000 Subject: [PATCH 109/148] Remove unused index-name field from release matrix --- .github/workflows/release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8b1cc52e2..26dd36c50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,11 +24,9 @@ jobs: include: - runner: ubuntu-latest torch-variant: cpu - index-name: gcp-release-registry-cpu publish-url: https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl - runner: gigl-gpu-instances torch-variant: cu128 - index-name: gcp-release-registry-cu128 publish-url: https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl-cu128 env: PROJECT_ID: ${{ vars.GCP_PROJECT_ID }} From ab3d60b92b08db995ecd68fb2f42055df95e5884 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sun, 26 Apr 2026 20:04:55 +0000 Subject: [PATCH 110/148] Clear stale cmake cache before gigl-core wheel build --- .github/workflows/release.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 26dd36c50..ca5e16988 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,7 +74,10 @@ jobs: - name: Build gigl-core wheel if: ${{ inputs.release_gigl_core }} working-directory: gigl-core - run: uv build --wheel --no-build-isolation + run: | + # Remove stale cmake cache from previous runs on self-hosted runners. + rm -rf .cache/cmake_build + uv build --wheel --no-build-isolation - name: Publish gigl-core wheel if: ${{ inputs.release_gigl_core }} From 0bb3d34fa5beb118b591ff0eac646870821555ca Mon Sep 17 00:00:00 2001 From: mkolodner Date: Sun, 26 Apr 2026 20:43:03 +0000 Subject: [PATCH 111/148] remove c++ manual check --- .github/workflows/release.yml | 8 ------- RELEASING.md | 45 ++++++++++------------------------- scripts/bump_version.py | 12 ++++++++++ 3 files changed, 25 insertions(+), 40 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ca5e16988..078d31c50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,11 +5,6 @@ on: # - building and releasing docker images # - building and releasing KFP pipeline workflow_dispatch: - inputs: - release_gigl_core: - description: "Release gigl-core wheel (only needed when C++ code changed)" - type: boolean - default: false permissions: contents: read @@ -70,9 +65,7 @@ jobs: # torch variant. Build and publish one wheel per variant. # --no-build-isolation: torch is not on PyPI; the build must use the ambient # environment where torch is already installed by make install_dev_deps. - # Only runs when release_gigl_core=true (i.e. when C++ code changed). - name: Build gigl-core wheel - if: ${{ inputs.release_gigl_core }} working-directory: gigl-core run: | # Remove stale cmake cache from previous runs on self-hosted runners. @@ -80,7 +73,6 @@ jobs: uv build --wheel --no-build-isolation - name: Publish gigl-core wheel - if: ${{ inputs.release_gigl_core }} working-directory: gigl-core run: | uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess diff --git a/RELEASING.md b/RELEASING.md index 88c2e2ee6..ba313764c 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -7,9 +7,8 @@ GiGL is distributed as two wheels that are always installed together: - **`gigl`** — pure Python (same wheel for CPU and CUDA users) - **`gigl-core`** — compiled C++/CUDA extensions, ABI-bound to the torch variant -Each has its own version. `gigl-core` is versioned **independently** — it only needs a new release when C++ code under -`gigl-core/` actually changes. `gigl` pins an exact `gigl-core` version in its `pyproject.toml`; that pin is updated in -the same PR as any C++ change. +Both wheels are always versioned and released together. `bump_version.py` updates both versions and keeps the +`gigl-core` pin in `gigl/pyproject.toml` in sync automatically. ## How to trigger a release @@ -18,43 +17,25 @@ Releases are triggered manually via the **Release GiGL** GitHub Actions workflow 1. Go to the **Actions** tab in the GitHub repository. 2. Select **Release GiGL** from the left sidebar. 3. Click **Run workflow** (top right of the workflow runs table). -4. A form appears with one input: - - **Release gigl-core wheel** — check this only if C++ code changed (see below). -5. Click **Run workflow** to start. +4. Click **Run workflow** to start. -The workflow runs two jobs in parallel — one on a CPU runner, one on a GPU runner — and publishes to both variant -registries. +The workflow runs two jobs in parallel — one on a CPU runner, one on a GPU runner — and publishes both `gigl` and +`gigl-core` wheels to both variant registries. -## Releasing gigl (Python-only change) +## Releasing GiGL -Use this when no files under `gigl-core/` were modified. - -1. Bump the version in `gigl/pyproject.toml` (`version = "X.Y.Z"`). -2. Open a PR, get it merged to `main`. -3. Trigger the **Release GiGL** workflow with **Release gigl-core wheel** unchecked. - -Both the CPU and CUDA `gigl` wheels are built and published. The existing `gigl-core` wheel in the registry continues to -satisfy the pinned dependency — no `gigl-core` action needed. - -## Releasing gigl-core (C++ changed) - -Use this when files under `gigl-core/csrc/` or `gigl-core/CMakeLists.txt` were modified. - -1. Bump the version in `gigl-core/pyproject.toml` (`version = "X.Y.Z"`). -2. Update the matching pin in `gigl/pyproject.toml`: `"gigl-core==X.Y.Z"`. -3. Open a PR with both version changes, get it merged to `main`. -4. Trigger the **Release GiGL** workflow with **Release gigl-core wheel** checked. - -This publishes new `gigl-core` wheels (cpu + cu128) **and** new `gigl` wheels (which carry the updated pin). +1. Run `bump_version.py` (or let `create_release.yml` handle it automatically for nightly builds). +2. Open a PR with the version bump, get it merged to `main`. +3. Trigger the **Release GiGL** workflow from the release branch. ## What gets published Each release run publishes to two self-contained registries: -| Registry | Packages | -| ---------------------------- | ------------------------------------------------------------------ | -| `gcp-release-registry-cpu` | `gigl` (pure Python) + `gigl-core` (CPU wheel, if releasing) | -| `gcp-release-registry-cu128` | `gigl` (pure Python) + `gigl-core` (CUDA 12.8 wheel, if releasing) | +| Registry | Packages | +| ---------------------------- | ----------------------------------------------------- | +| `gcp-release-registry-cpu` | `gigl` (pure Python) + `gigl-core` (CPU wheel) | +| `gcp-release-registry-cu128` | `gigl` (pure Python) + `gigl-core` (CUDA 12.8 wheel) | Users install from exactly one registry based on their variant — see [installation docs](docs/user_guide/getting_started/installation.md). diff --git a/scripts/bump_version.py b/scripts/bump_version.py index 49cbaab1f..499f99ed9 100644 --- a/scripts/bump_version.py +++ b/scripts/bump_version.py @@ -100,6 +100,17 @@ def update_pyproject(version: str) -> None: with open(path, "r") as f: content = f.read() content = re.sub(r'(version\s*)=\s*"[\d\.]+"', f'\\1= "{version}"', content) + # Keep the gigl-core pin in sync with the new version. + content = re.sub(r'"gigl-core==[\d\.a-zA-Z]+"', f'"gigl-core=={version}"', content) + with open(path, "w") as f: + f.write(content) + + +def update_gigl_core_pyproject(version: str) -> None: + path = f"{GIGL_ROOT_DIR}/gigl-core/pyproject.toml" + with open(path, "r") as f: + content = f.read() + content = re.sub(r'(version\s*)=\s*"[\d\.]+"', f'\\1= "{version}"', content) with open(path, "w") as f: f.write(content) @@ -161,6 +172,7 @@ def bump_version( ) update_version(version=new_version) update_pyproject(version=new_version) + update_gigl_core_pyproject(version=new_version) print( f"Bumped to GiGL Version: {new_version}! To release, raise a PR with these changes and after it is merged, tag main with the version and run make release_gigl." From 495c19da467511dfe96e3a829b87b22f0cbd37c7 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 18:04:27 +0000 Subject: [PATCH 112/148] Comments --- .gitignore | 2 +- requirements/install_cpp_deps.sh | 6 ------ requirements/install_py_deps.sh | 15 +++------------ 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 6219614ac..8bbaf1d0d 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,7 @@ fossa*.zip gha-creds-*.json # Compiled C++ extension modules -gigl/csrc/**/*.so +gigl-core/**/*.so # Local-only scripts with hardcoded internal identifiers scripts/_local/ diff --git a/requirements/install_cpp_deps.sh b/requirements/install_cpp_deps.sh index d3e0a4353..912bdee1a 100644 --- a/requirements/install_cpp_deps.sh +++ b/requirements/install_cpp_deps.sh @@ -17,14 +17,8 @@ if [ "$(uname)" == "Darwin" ]; then exit 1 fi -# On Linux, apt-get installs versioned binaries (e.g. clang-format-15) directly -# into /usr/bin. No PATH changes are needed since /usr/bin is already on PATH. -# Callers use the versioned names (clang-format-15, clang-tidy-15, clangd-15) -# directly so the version is explicit and greppable across the codebase. # clang++-15 requires libstdc++-12-dev: on Ubuntu 22.04, clang++-15 looks for GCC 12 # headers. Without this package clang++-15 cannot find standard headers like . -# clang++-15 itself is needed because generate_compile_commands.py rewrites -# compile_commands.json to use it so clangd natively understands the commands. sudo apt-get update -y sudo apt-get install -y clang-format-15 clang-tidy-15 clangd-15 clang++-15 libstdc++-12-dev cmake diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index d3e1cbdaa..f86bad005 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -138,18 +138,12 @@ install_gigl_lib_deps() { flag_use_inexact_match="--inexact" fi - # --no-install-project: skip building and installing the root gigl package here. - # gigl (pure Python) is installed separately via `uv pip install .` in *.src Dockerfiles. - # gigl-core (C++ extensions) is a path dependency — it IS installed here from the stub - # files (pyproject.toml + CMakeLists.txt) copied into the base image. With no C++ sources - # present, cmake configures but compiles nothing, producing an empty wheel. - # The *.src Dockerfiles copy the full gigl-core source and reinstall the real wheel. if [[ $DEV -eq 1 ]] then # https://docs.astral.sh/uv/reference/cli/#uv-sync - uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} --no-install-project + uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} else - uv sync ${extra_deps_clause[@]} --group cpp-build --locked ${flag_use_inexact_match} --no-install-project + uv sync ${extra_deps_clause[@]} --group cpp-build --locked ${flag_use_inexact_match} fi # Taken from https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script @@ -157,10 +151,7 @@ install_gigl_lib_deps() { if [[ "${SKIP_GLT_POST_INSTALL}" -eq 0 ]] then SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - # --no-project: prevents uv from trying to install the gigl project before running - # the script. We intentionally skipped installing it above (--no-install-project), - # and post_install.py only runs install_glt.sh — it does not need gigl installed. - uv run --no-project python $SCRIPT_DIR/../gigl/scripts/post_install.py + uv run python $SCRIPT_DIR/../gigl/scripts/post_install.py fi } From 2f0f753f815414143dcfdf44d94d2007c954621f Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 18:32:33 +0000 Subject: [PATCH 113/148] Update --- gigl-core/CMakeLists.txt | 18 +++++++++++--- pyproject.toml | 9 ------- requirements/install_py_deps.sh | 2 +- uv.lock | 43 --------------------------------- 4 files changed, 16 insertions(+), 56 deletions(-) diff --git a/gigl-core/CMakeLists.txt b/gigl-core/CMakeLists.txt index d4afbf690..5b0e6d9f2 100644 --- a/gigl-core/CMakeLists.txt +++ b/gigl-core/CMakeLists.txt @@ -56,14 +56,26 @@ if(_PYTHON_SRCS) endif() endforeach() - if(NOT pybind11_DIR) - message(FATAL_ERROR "Cannot find pybind11 cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") + # pybind11 is provided by the scikit-build-core isolated build env when building a + # wheel. For direct cmake invocations (make unit_test_cpp), fall back to FetchContent + # so pybind11 does not need to be pre-installed in the dev venv. + if(pybind11_DIR) + find_package(pybind11 CONFIG REQUIRED) + else() + include(FetchContent) + FetchContent_Declare( + pybind11 + GIT_REPOSITORY https://github.com/pybind/pybind11.git + GIT_TAG v2.13.6 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(pybind11) endif() + if(NOT TORCH_CMAKE_PREFIX) message(FATAL_ERROR "Cannot find torch cmake config in CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}. Run: make install_dev_deps") endif() - find_package(pybind11 CONFIG REQUIRED) find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") # torch_python provides the pybind11 type casters for at::Tensor. It is not diff --git a/pyproject.toml b/pyproject.toml index e970df498..40fb17ac1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,18 +102,9 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", ] -# gigl-core must build against torch, which is not on PyPI. An isolated build -# environment would fail to find it, so we disable isolation and let the build -# use the ambient environment where torch is already installed. -no-build-isolation-package = ["gigl-core"] [dependency-groups] -cpp-build = [ - "scikit-build-core>=0.10", - "pybind11>=2.12", -] dev = [ - {include-group = "cpp-build"}, {include-group = "docs"}, {include-group = "lint"}, {include-group = "test"}, diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index f86bad005..6a328165e 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -143,7 +143,7 @@ install_gigl_lib_deps() { # https://docs.astral.sh/uv/reference/cli/#uv-sync uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} else - uv sync ${extra_deps_clause[@]} --group cpp-build --locked ${flag_use_inexact_match} + uv sync ${extra_deps_clause[@]} --locked ${flag_use_inexact_match} fi # Taken from https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script diff --git a/uv.lock b/uv.lock index baae02ddc..30d4020a7 100644 --- a/uv.lock +++ b/uv.lock @@ -769,10 +769,6 @@ transform = [ ] [package.dev-dependencies] -cpp-build = [ - { name = "pybind11" }, - { name = "scikit-build-core" }, -] dev = [ { name = "astroid" }, { name = "mdformat" }, @@ -788,10 +784,8 @@ dev = [ { name = "pandas-stubs" }, { name = "parameterized" }, { name = "pre-commit" }, - { name = "pybind11" }, { name = "pydata-sphinx-theme" }, { name = "ruff" }, - { name = "scikit-build-core" }, { name = "sphinx" }, { name = "sphinx-autoapi" }, { name = "sphinx-autodoc-typehints" }, @@ -897,10 +891,6 @@ requires-dist = [ provides-extras = ["transform", "pyg27-torch28-cpu", "pyg27-torch28-cu128", "experimental"] [package.metadata.requires-dev] -cpp-build = [ - { name = "pybind11", specifier = ">=2.12" }, - { name = "scikit-build-core", specifier = ">=0.10" }, -] dev = [ { name = "astroid", specifier = "==3.3.11" }, { name = "mdformat", specifier = "==0.7.22" }, @@ -916,10 +906,8 @@ dev = [ { name = "pandas-stubs", specifier = "==2.2.2.240807" }, { name = "parameterized", specifier = "==0.9.0" }, { name = "pre-commit", specifier = "==3.3.2" }, - { name = "pybind11", specifier = ">=2.12" }, { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, { name = "ruff", specifier = "==0.15.10" }, - { name = "scikit-build-core", specifier = ">=0.10" }, { name = "sphinx", specifier = "==7.4.7" }, { name = "sphinx-autoapi", specifier = "==3.6.0" }, { name = "sphinx-autodoc-typehints", specifier = "==2.3.0" }, @@ -2843,15 +2831,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] -[[package]] -name = "pathspec" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/17/9c3094b822982b9f1ea666d8580ce59000f61f87c1663556fb72031ad9ec/pathspec-1.1.0.tar.gz", hash = "sha256:f5d7c555da02fd8dde3e4a2354b6aba817a89112fa8f333f7917a2a4834dd080", size = 133918, upload-time = "2026-04-23T01:46:22.298Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/c9/8eed0486f074e9f1ca7f8ce5ad663e65f12fdab344028d658fa1b03d35e0/pathspec-1.1.0-py3-none-any.whl", hash = "sha256:574b128f7456bd899045ccd142dd446af7e6cfd0072d63ad73fbc55fbb4aaa42", size = 56264, upload-time = "2026-04-23T01:46:20.606Z" }, -] - [[package]] name = "pexpect" version = "4.9.0" @@ -3076,15 +3055,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] -[[package]] -name = "pybind11" -version = "3.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/f0/35145a3c3baffeef55d4b8324caa33abaa8fa56ab345ecd4b2211d09163e/pybind11-3.0.4.tar.gz", hash = "sha256:3286b59c8a774b9ee650169302dd5a4eedc30a8617905a0560dd8ee44775130c", size = 589533, upload-time = "2026-04-19T03:08:15.925Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/06/c3a23c9a0263b136c519f033a58d4641e73065fefc7754e9667ec206d992/pybind11-3.0.4-py3-none-any.whl", hash = "sha256:961720ee652da51d531b7b2451a6bd2bc042b0106e6d9baa48ecb7d58034ce63", size = 314166, upload-time = "2026-04-19T03:08:14.091Z" }, -] - [[package]] name = "pycparser" version = "2.23" @@ -3548,19 +3518,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, ] -[[package]] -name = "scikit-build-core" -version = "0.12.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "pathspec" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/cd/9ebb50029b6d8a3ee9e38cdce514ebd70190ec1edf28ab0a1f66d0b84670/scikit_build_core-0.12.2.tar.gz", hash = "sha256:562e0bbc9de1a354c87825ccf732080268d6582a0200f648e8c4a2dcb1e3736d", size = 303553, upload-time = "2026-03-05T18:25:57.666Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/49/b2f0fbe3165d55c02e7f9eec6a10685d518af0ef6e919ff2f589c2d15c85/scikit_build_core-0.12.2-py3-none-any.whl", hash = "sha256:6ea4730da400f9a998ec3287bd3ebc1d751fe45ad0a93451bead8618adbc02b1", size = 192625, upload-time = "2026-03-05T18:25:56.207Z" }, -] - [[package]] name = "scikit-learn" version = "1.7.2" From 294e4d22e9670cf57194d153407e2915590ccba0 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 18:43:23 +0000 Subject: [PATCH 114/148] update releasing guide --- RELEASING.md | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index ba313764c..10f2606e1 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -10,23 +10,46 @@ GiGL is distributed as two wheels that are always installed together: Both wheels are always versioned and released together. `bump_version.py` updates both versions and keeps the `gigl-core` pin in `gigl/pyproject.toml` in sync automatically. -## How to trigger a release +## Release process -Releases are triggered manually via the **Release GiGL** GitHub Actions workflow (`release.yml`): +A full release involves two GitHub Actions workflows run in sequence. + +### Step 1 — Create Release (`create_release.yml`) + +This workflow bumps the version, creates the release branch and tag, releases the KFP pipeline, and opens the +merge-back PR. Trigger it manually: 1. Go to the **Actions** tab in the GitHub repository. +2. Select **Create Release** from the left sidebar. +3. Click **Run workflow**, choose the bump type (`major`, `minor`, or `patch`), and click **Run workflow**. + +The workflow will: + +- Bump the version in `pyproject.toml` (both `gigl` and `gigl-core`) and commit it to a new `release/vX.Y.Z` branch. +- Release the GiGL KFP pipeline from that branch. +- Create and push a version tag `vX.Y.Z`. +- Open a PR to merge `release/vX.Y.Z` back to `main`. + +### Step 2 — Release GiGL (`release.yml`) + +This workflow builds and publishes the `gigl` and `gigl-core` wheels. Trigger it from the release branch created in +Step 1: + +1. Go to the **Actions** tab. 2. Select **Release GiGL** from the left sidebar. -3. Click **Run workflow** (top right of the workflow runs table). -4. Click **Run workflow** to start. +3. Click **Run workflow**, select the `release/vX.Y.Z` branch from the branch dropdown, and click **Run workflow**. + +The workflow runs two jobs in parallel — one on a CPU runner, one on a GPU runner — and publishes both wheels to both +variant registries. + +### Step 3 — Merge the PR -The workflow runs two jobs in parallel — one on a CPU runner, one on a GPU runner — and publishes both `gigl` and -`gigl-core` wheels to both variant registries. +Once both workflows succeed, merge the PR opened by **Create Release** to bring the version bump back into `main`. -## Releasing GiGL +## Nightly releases -1. Run `bump_version.py` (or let `create_release.yml` handle it automatically for nightly builds). -2. Open a PR with the version bump, get it merged to `main`. -3. Trigger the **Release GiGL** workflow from the release branch. +Nightly builds are triggered automatically by `nightly_release_&_test.yml`, which calls `create_release.yml` with +`bump_type=nightly`. The **Release GiGL** wheel-publish step is not part of the nightly flow. ## What gets published From d4f01268c5305ebae3157410adaa34f938b200ed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 27 Apr 2026 18:53:51 +0000 Subject: [PATCH 115/148] [AUTOMATED] Update dep.vars, and other relevant files with new image names --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- gigl/dep_vars.env | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index 263d8cace..88c69e2f5 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:294e4d22e9670cf57194d153407e2915590ccba0.104.1 entrypoint: /bin/bash args: - -c diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index a458e2b48..8b95d4d1d 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:308fd672e80333c9196a72efb86e6f07b2b16192.103.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:294e4d22e9670cf57194d153407e2915590ccba0.104.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:294e4d22e9670cf57194d153407e2915590ccba0.104.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:294e4d22e9670cf57194d153407e2915590ccba0.104.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 From cb1ebb0f9bf1d43e9e2237921a460d0dcb417a27 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 20:17:24 +0000 Subject: [PATCH 116/148] Update --- .github/workflows/release.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 078d31c50..b158eb5cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,13 +63,16 @@ jobs: # gigl-core contains compiled C++/CUDA extensions that are ABI-bound to the # torch variant. Build and publish one wheel per variant. - # --no-build-isolation: torch is not on PyPI; the build must use the ambient - # environment where torch is already installed by make install_dev_deps. + # --no-build-isolation: torch is not on PyPI so an isolated build env cannot + # install it; cmake must find torch from the ambient environment installed by + # make install_dev_deps. scikit-build-core is pre-installed explicitly because + # --no-build-isolation skips the automatic installation of [build-system].requires. - name: Build gigl-core wheel working-directory: gigl-core run: | # Remove stale cmake cache from previous runs on self-hosted runners. rm -rf .cache/cmake_build + uv pip install "scikit-build-core>=0.10" uv build --wheel --no-build-isolation - name: Publish gigl-core wheel From 03a217533de816cdc8598a426d96abccdfc155ac Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 20:34:41 +0000 Subject: [PATCH 117/148] Update --- .github/workflows/release.yml | 13 +++++-------- pyproject.toml | 10 ++++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b158eb5cc..a90284c32 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,17 +63,14 @@ jobs: # gigl-core contains compiled C++/CUDA extensions that are ABI-bound to the # torch variant. Build and publish one wheel per variant. - # --no-build-isolation: torch is not on PyPI so an isolated build env cannot - # install it; cmake must find torch from the ambient environment installed by - # make install_dev_deps. scikit-build-core is pre-installed explicitly because - # --no-build-isolation skips the automatic installation of [build-system].requires. + # Build isolation is disabled via no-build-isolation-package in pyproject.toml + # so cmake can find torch from the ambient environment (not on PyPI). + # scikit-build-core is declared in extra-build-dependencies and installed by uv. - name: Build gigl-core wheel - working-directory: gigl-core run: | # Remove stale cmake cache from previous runs on self-hosted runners. - rm -rf .cache/cmake_build - uv pip install "scikit-build-core>=0.10" - uv build --wheel --no-build-isolation + rm -rf gigl-core/.cache/cmake_build + uv build --wheel gigl-core/ - name: Publish gigl-core wheel working-directory: gigl-core diff --git a/pyproject.toml b/pyproject.toml index 40fb17ac1..36cca94a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,6 +102,16 @@ required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", ] +# gigl-core must build against torch, which is not on PyPI and cannot be installed +# into an isolated build environment. Disabling isolation lets cmake find torch from +# the ambient venv (installed by make install_dev_deps / base Docker images). +no-build-isolation-package = ["gigl-core"] + +[tool.uv.extra-build-dependencies] +# scikit-build-core is gigl-core's PEP 517 build backend. With build isolation +# disabled it is not auto-installed from [build-system].requires, so uv installs +# it into the project venv before invoking the build backend. +gigl-core = ["scikit-build-core>=0.10"] [dependency-groups] dev = [ From 525f8fccccec71daf2381ea1ab4d7891c449c0ef Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 20:49:54 +0000 Subject: [PATCH 118/148] Update --- pyproject.toml | 11 +++++------ requirements/install_py_deps.sh | 2 +- uv.lock | 28 ++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 36cca94a0..35a0cef35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,14 +107,13 @@ required-environments = [ # the ambient venv (installed by make install_dev_deps / base Docker images). no-build-isolation-package = ["gigl-core"] -[tool.uv.extra-build-dependencies] -# scikit-build-core is gigl-core's PEP 517 build backend. With build isolation -# disabled it is not auto-installed from [build-system].requires, so uv installs -# it into the project venv before invoking the build backend. -gigl-core = ["scikit-build-core>=0.10"] - [dependency-groups] +# scikit-build-core is gigl-core's PEP 517 build backend. With no-build-isolation-package +# set, uv does not install [build-system].requires automatically, so it must be present +# in the ambient environment before any gigl-core build (uv sync, uv build, Dockerfiles). +build-backend = ["scikit-build-core>=0.10"] dev = [ + {include-group = "build-backend"}, {include-group = "docs"}, {include-group = "lint"}, {include-group = "test"}, diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index 6a328165e..edb9c700a 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -143,7 +143,7 @@ install_gigl_lib_deps() { # https://docs.astral.sh/uv/reference/cli/#uv-sync uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} else - uv sync ${extra_deps_clause[@]} --locked ${flag_use_inexact_match} + uv sync ${extra_deps_clause[@]} --group build-backend --locked ${flag_use_inexact_match} fi # Taken from https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script diff --git a/uv.lock b/uv.lock index 30d4020a7..8774acac8 100644 --- a/uv.lock +++ b/uv.lock @@ -769,6 +769,9 @@ transform = [ ] [package.dev-dependencies] +build-backend = [ + { name = "scikit-build-core" }, +] dev = [ { name = "astroid" }, { name = "mdformat" }, @@ -786,6 +789,7 @@ dev = [ { name = "pre-commit" }, { name = "pydata-sphinx-theme" }, { name = "ruff" }, + { name = "scikit-build-core" }, { name = "sphinx" }, { name = "sphinx-autoapi" }, { name = "sphinx-autodoc-typehints" }, @@ -891,6 +895,7 @@ requires-dist = [ provides-extras = ["transform", "pyg27-torch28-cpu", "pyg27-torch28-cu128", "experimental"] [package.metadata.requires-dev] +build-backend = [{ name = "scikit-build-core", specifier = ">=0.10" }] dev = [ { name = "astroid", specifier = "==3.3.11" }, { name = "mdformat", specifier = "==0.7.22" }, @@ -908,6 +913,7 @@ dev = [ { name = "pre-commit", specifier = "==3.3.2" }, { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, { name = "ruff", specifier = "==0.15.10" }, + { name = "scikit-build-core", specifier = ">=0.10" }, { name = "sphinx", specifier = "==7.4.7" }, { name = "sphinx-autoapi", specifier = "==3.6.0" }, { name = "sphinx-autodoc-typehints", specifier = "==2.3.0" }, @@ -2831,6 +2837,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + [[package]] name = "pexpect" version = "4.9.0" @@ -3518,6 +3533,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, ] +[[package]] +name = "scikit-build-core" +version = "0.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pathspec" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/cd/9ebb50029b6d8a3ee9e38cdce514ebd70190ec1edf28ab0a1f66d0b84670/scikit_build_core-0.12.2.tar.gz", hash = "sha256:562e0bbc9de1a354c87825ccf732080268d6582a0200f648e8c4a2dcb1e3736d", size = 303553, upload-time = "2026-03-05T18:25:57.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/49/b2f0fbe3165d55c02e7f9eec6a10685d518af0ef6e919ff2f589c2d15c85/scikit_build_core-0.12.2-py3-none-any.whl", hash = "sha256:6ea4730da400f9a998ec3287bd3ebc1d751fe45ad0a93451bead8618adbc02b1", size = 192625, upload-time = "2026-03-05T18:25:56.207Z" }, +] + [[package]] name = "scikit-learn" version = "1.7.2" From ed8798936ce4a92cc54f6799131198718a9b4c9a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 27 Apr 2026 21:01:40 +0000 Subject: [PATCH 119/148] [AUTOMATED] Update dep.vars, and other relevant files with new image names --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- gigl/dep_vars.env | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index 88c69e2f5..c93ccf8b0 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:294e4d22e9670cf57194d153407e2915590ccba0.104.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 entrypoint: /bin/bash args: - -c diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index 8b95d4d1d..ef0f137a8 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:294e4d22e9670cf57194d153407e2915590ccba0.104.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:294e4d22e9670cf57194d153407e2915590ccba0.104.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:294e4d22e9670cf57194d153407e2915590ccba0.104.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 From 6bb8943bf82a6870091edb92dda268a4443f4631 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 22:44:37 +0000 Subject: [PATCH 120/148] Address some comments --- .clangd | 2 + .github/workflows/release.yml | 23 +++--- Makefile | 14 ++-- .../getting_started/installation.md | 2 +- scripts/generate_compile_commands.py | 78 ------------------- scripts/run_cpp_lint.py | 9 ++- 6 files changed, 25 insertions(+), 103 deletions(-) create mode 100644 .clangd delete mode 100644 scripts/generate_compile_commands.py diff --git a/.clangd b/.clangd new file mode 100644 index 000000000..d1812104f --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + CompilationDatabase: gigl-core/.cache/cmake_build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a90284c32..8370cbd26 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,9 +32,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install cmake - run: sudo apt-get install -y cmake - - name: Setup Python deps and gcloud uses: ./.github/actions/setup-python-tools with: @@ -53,19 +50,11 @@ jobs: # Pre-install keyring and Artifact Registry plugin from the public PyPI uv tool install keyring --with keyrings.google-artifactregistry-auth==1.1.2 - # gigl is pure Python — build is fast and produces the same wheel on both - # runners. Publish to each variant's registry so the registry is - # self-contained: a user only needs one GCP extra-index URL per variant. - - name: Build and publish gigl wheel - run: | - uv build --wheel - uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess - # gigl-core contains compiled C++/CUDA extensions that are ABI-bound to the # torch variant. Build and publish one wheel per variant. # Build isolation is disabled via no-build-isolation-package in pyproject.toml # so cmake can find torch from the ambient environment (not on PyPI). - # scikit-build-core is declared in extra-build-dependencies and installed by uv. + # scikit-build-core is declared in the build-backend dependency group and installed by uv. - name: Build gigl-core wheel run: | # Remove stale cmake cache from previous runs on self-hosted runners. @@ -76,3 +65,13 @@ jobs: working-directory: gigl-core run: | uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess + + # gigl is pure Python — build is fast and produces the same wheel on both + # runners. Publish to each variant's registry so the registry is + # self-contained: a user only needs one GCP extra-index URL per variant. + # gigl-core is published first so its dependency is already in the registry + # when gigl becomes available. + - name: Build and publish gigl wheel + run: | + uv build --wheel + uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess diff --git a/Makefile b/Makefile index 60508fba7..0cbb3cdb9 100644 --- a/Makefile +++ b/Makefile @@ -51,9 +51,9 @@ check_if_valid_env: # if developing, you need to install dev deps instead install_dev_deps: check_if_valid_env gcloud auth configure-docker us-central1-docker.pkg.dev + bash ./requirements/install_cpp_deps.sh bash ./requirements/install_py_deps.sh --dev bash ./requirements/install_scala_deps.sh - bash ./requirements/install_cpp_deps.sh uv pip install -e . uv run pre-commit install --hook-type pre-commit --hook-type pre-push @@ -182,18 +182,15 @@ gigl-core/.cache/cmake_build/CMakeInit.txt: $(shell find gigl-core/csrc \( -name build_cpp_extensions: gigl-core/.cache/cmake_build/CMakeInit.txt -generate_compile_commands: gigl-core/.cache/cmake_build/CMakeInit.txt - uv run python -m scripts.generate_compile_commands - -check_lint_cpp: generate_compile_commands +check_lint_cpp: build_cpp_extensions $(if $(CPP_SOURCES_NO_CUDA),uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA)) # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, # changes expressions, adds/removes keywords), not just style. Run manually and # review the diff before committing. Note: --fix cannot auto-repair every check; # some violations require manual edits. -fix_lint_cpp: generate_compile_commands - $(if $(CPP_SOURCES_NO_CUDA),clang-tidy-15 --fix -p .cache/compile_commands.json $(CPP_SOURCES_NO_CUDA)) +fix_lint_cpp: build_cpp_extensions + $(if $(CPP_SOURCES_NO_CUDA),clang-tidy-15 --fix -p gigl-core/.cache/cmake_build/compile_commands.json $(CPP_SOURCES_NO_CUDA)) lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" @@ -201,7 +198,7 @@ lint_test: check_format assert_yaml_configs_parse check_lint_cpp # Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent # after switching between branches with substantially different CMakeLists.txt structure. clean_cpp: - rm -rf .cache/cpp_tests .cache/cmake_build_lint gigl-core/.cache/cmake_build + rm -rf .cache/cpp_tests gigl-core/.cache/cmake_build # compiles current working state of scala projects to local jars compile_jars: @@ -367,7 +364,6 @@ clean_build_files_scala: clean_build_files_cpp: rm -rf .cache/cpp_tests - rm -f .cache/compile_commands.json clean_build_files: clean_build_files_py clean_build_files_scala clean_build_files_cpp diff --git a/docs/user_guide/getting_started/installation.md b/docs/user_guide/getting_started/installation.md index 9955193c1..b823837a8 100644 --- a/docs/user_guide/getting_started/installation.md +++ b/docs/user_guide/getting_started/installation.md @@ -6,7 +6,7 @@ These are the current environments supported by GiGL | Python | Mac (Arm64) CPU | Linux CPU | Linux CUDA | PyTorch | PyG | | ------ | --------------- | --------- | ---------- | ------- | --- | -| 3.9 | Partial Support | Supported | 12.1 | 2.5 | 2.5 | +| 3.11 | Supported | Supported | 12.8 | 2.8 | 2.7 | ## Available Versions diff --git a/scripts/generate_compile_commands.py b/scripts/generate_compile_commands.py deleted file mode 100644 index 4500da3dd..000000000 --- a/scripts/generate_compile_commands.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Generate .cache/compile_commands.json for clangd. - -Delegates to CMake (which already knows all include paths and compiler flags via -find_package(Torch)) rather than manually constructing the database. - -CMake is configured with clang++-15 directly so clangd natively understands the -commands without needing a ``--query-driver`` workaround. This cmake invocation -is only for generating compile_commands.json — the actual extension build (via -``uv pip install -e gigl-core/``) uses the system default compiler independently. - -Primary use: called by ``run_cpp_lint.py`` before running clangd checks, and -by ``make generate_compile_commands`` when you need to refresh the database -manually (e.g. after adding new source files or changing compiler flags). - -Usage:: - - make generate_compile_commands -""" - -import subprocess -from pathlib import Path - -_REPO_ROOT: Path = Path(__file__).resolve().parent.parent -_GIGL_CORE_DIR: Path = _REPO_ROOT / "gigl-core" -# CMakeInit.txt is generated by scikit-build-core during `uv pip install -e gigl-core/`. -# It sets CMAKE_PREFIX_PATH to the environment's site-packages so CMake can find -# pybind11 and torch. Must exist before this script is called (run build_cpp_extensions). -_GIGL_CORE_CMAKE_INIT: Path = ( - _GIGL_CORE_DIR / ".cache" / "cmake_build" / "CMakeInit.txt" -) -_CMAKE_BUILD_DIR: Path = _REPO_ROOT / ".cache" / "cmake_build_lint" -COMPILE_COMMANDS: Path = _REPO_ROOT / ".cache" / "compile_commands.json" - - -def write_compile_commands() -> None: - """Run CMake to generate .cache/compile_commands.json. - - Configures gigl-core's CMakeLists.txt with clang++-15, loading - ``gigl-core/.cache/cmake_build/CMakeInit.txt`` (written by - ``uv pip install -e gigl-core/``) for the correct ``CMAKE_PREFIX_PATH``. - """ - if not _GIGL_CORE_CMAKE_INIT.exists(): - raise FileNotFoundError( - f"{_GIGL_CORE_CMAKE_INIT} not found. " - "Run `make build_cpp_extensions` first to generate it." - ) - _CMAKE_BUILD_DIR.mkdir(parents=True, exist_ok=True) - result = subprocess.run( - [ - "cmake", - "-C", - str(_GIGL_CORE_CMAKE_INIT), - "-S", - str(_GIGL_CORE_DIR), - "-B", - str(_CMAKE_BUILD_DIR), - "-DCMAKE_CXX_COMPILER=clang++-15", - "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", - ], - capture_output=True, - text=True, - ) - if result.returncode != 0: - raise RuntimeError( - f"CMake configure failed (exit {result.returncode}):\n{result.stderr}" - ) - - raw_path = _CMAKE_BUILD_DIR / "compile_commands.json" - COMPILE_COMMANDS.write_text(raw_path.read_text()) - - -def main() -> None: - write_compile_commands() - print(f"Wrote {COMPILE_COMMANDS}") - - -if __name__ == "__main__": - main() diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 2009e285d..6ffa23b20 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -1,8 +1,9 @@ """Run C++ lint on source files using clangd. Runs clangd --check on each file in parallel and prints a clean summary. -Expects compile_commands.json to already exist at .cache/compile_commands.json; -call ``make generate_compile_commands`` first if it is absent or stale +Expects compile_commands.json to already exist at +gigl-core/.cache/cmake_build/compile_commands.json; call +``make build_cpp_extensions`` first if it is absent or stale (``make check_lint_cpp`` does this automatically via a Makefile prerequisite). Usage:: @@ -16,7 +17,8 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path -from scripts.generate_compile_commands import COMPILE_COMMANDS +_REPO_ROOT = Path(__file__).resolve().parent.parent +COMPILE_COMMANDS = _REPO_ROOT / "gigl-core" / ".cache" / "cmake_build" / "compile_commands.json" # Matches real clang-tidy diagnostics emitted by clangd: # E[HH:MM:SS.mmm] [check-name] Line N: message @@ -29,6 +31,7 @@ def _check_file(source: Path) -> list[str]: "clangd-15", f"--check={source}", f"--compile-commands-dir={COMPILE_COMMANDS.parent}", + "--query-driver=/usr/bin/clang++-15,/usr/bin/g++", ], capture_output=True, text=True, From 8282bbc57eb1c389f090c78195fb371dbb88a1fe Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 22:45:02 +0000 Subject: [PATCH 121/148] Format --- RELEASING.md | 16 ++++++++-------- scripts/run_cpp_lint.py | 4 +++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 10f2606e1..602253bee 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -16,8 +16,8 @@ A full release involves two GitHub Actions workflows run in sequence. ### Step 1 — Create Release (`create_release.yml`) -This workflow bumps the version, creates the release branch and tag, releases the KFP pipeline, and opens the -merge-back PR. Trigger it manually: +This workflow bumps the version, creates the release branch and tag, releases the KFP pipeline, and opens the merge-back +PR. Trigger it manually: 1. Go to the **Actions** tab in the GitHub repository. 2. Select **Create Release** from the left sidebar. @@ -32,8 +32,8 @@ The workflow will: ### Step 2 — Release GiGL (`release.yml`) -This workflow builds and publishes the `gigl` and `gigl-core` wheels. Trigger it from the release branch created in -Step 1: +This workflow builds and publishes the `gigl` and `gigl-core` wheels. Trigger it from the release branch created in Step +1: 1. Go to the **Actions** tab. 2. Select **Release GiGL** from the left sidebar. @@ -55,10 +55,10 @@ Nightly builds are triggered automatically by `nightly_release_&_test.yml`, whic Each release run publishes to two self-contained registries: -| Registry | Packages | -| ---------------------------- | ----------------------------------------------------- | -| `gcp-release-registry-cpu` | `gigl` (pure Python) + `gigl-core` (CPU wheel) | -| `gcp-release-registry-cu128` | `gigl` (pure Python) + `gigl-core` (CUDA 12.8 wheel) | +| Registry | Packages | +| ---------------------------- | ---------------------------------------------------- | +| `gcp-release-registry-cpu` | `gigl` (pure Python) + `gigl-core` (CPU wheel) | +| `gcp-release-registry-cu128` | `gigl` (pure Python) + `gigl-core` (CUDA 12.8 wheel) | Users install from exactly one registry based on their variant — see [installation docs](docs/user_guide/getting_started/installation.md). diff --git a/scripts/run_cpp_lint.py b/scripts/run_cpp_lint.py index 6ffa23b20..7e2db01c9 100644 --- a/scripts/run_cpp_lint.py +++ b/scripts/run_cpp_lint.py @@ -18,7 +18,9 @@ from pathlib import Path _REPO_ROOT = Path(__file__).resolve().parent.parent -COMPILE_COMMANDS = _REPO_ROOT / "gigl-core" / ".cache" / "cmake_build" / "compile_commands.json" +COMPILE_COMMANDS = ( + _REPO_ROOT / "gigl-core" / ".cache" / "cmake_build" / "compile_commands.json" +) # Matches real clang-tidy diagnostics emitted by clangd: # E[HH:MM:SS.mmm] [check-name] Line N: message From 8dbd4c4806308903365385df15e18a88f95c7c2a Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 23:11:50 +0000 Subject: [PATCH 122/148] Address comments --- .github/workflows/on-pr-comment.yml | 2 +- .github/workflows/on-pr-merge.yml | 2 +- Makefile | 35 ++++---------- RELEASING.md | 2 +- docs/cpp_style_guide.md | 10 ++-- gigl-core/Makefile | 46 +++++++++++++++++++ .../requirements}/install_cpp_deps.sh | 2 +- pyproject.toml | 4 +- requirements/install_py_deps.sh | 2 +- 9 files changed, 67 insertions(+), 38 deletions(-) create mode 100644 gigl-core/Makefile rename {requirements => gigl-core/requirements}/install_cpp_deps.sh (95%) diff --git a/.github/workflows/on-pr-comment.yml b/.github/workflows/on-pr-comment.yml index 53ab9b146..39734edb5 100644 --- a/.github/workflows/on-pr-comment.yml +++ b/.github/workflows/on-pr-comment.yml @@ -78,7 +78,7 @@ jobs: descriptive_workflow_name: "C++ Unit Test" use_cloud_run: "false" command: | - bash requirements/install_cpp_deps.sh + bash gigl-core/requirements/install_cpp_deps.sh make unit_test_cpp unit-test-scala: diff --git a/.github/workflows/on-pr-merge.yml b/.github/workflows/on-pr-merge.yml index 81f9f37d8..497df6cad 100644 --- a/.github/workflows/on-pr-merge.yml +++ b/.github/workflows/on-pr-merge.yml @@ -77,7 +77,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install C++ dependencies - run: bash requirements/install_cpp_deps.sh + run: bash gigl-core/requirements/install_cpp_deps.sh - name: Run C++ Unit Tests run: make unit_test_cpp diff --git a/Makefile b/Makefile index 0cbb3cdb9..a2349c6c7 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ check_if_valid_env: # if developing, you need to install dev deps instead install_dev_deps: check_if_valid_env gcloud auth configure-docker us-central1-docker.pkg.dev - bash ./requirements/install_cpp_deps.sh + bash ./gigl-core/requirements/install_cpp_deps.sh bash ./requirements/install_py_deps.sh --dev bash ./requirements/install_scala_deps.sh uv pip install -e . @@ -99,14 +99,8 @@ unit_test_scala: clean_build_files_scala # Eventually, we should look into splitting these up. # We run `make check_format` separately instead of as a dependent make rule so that it always runs after the actual testing. # We don't want to fail the tests due to non-conformant formatting during development. -.cache/cpp_tests/.configured: gigl-core/CMakeLists.txt gigl-core/tests/CMakeLists.txt gigl-core/.cache/cmake_build/CMakeInit.txt - uv run cmake -C gigl-core/.cache/cmake_build/CMakeInit.txt \ - -S gigl-core -B .cache/cpp_tests -DGIGL_CORE_BUILD_TESTS=ON - touch .cache/cpp_tests/.configured - -unit_test_cpp: .cache/cpp_tests/.configured - uv run cmake --build .cache/cpp_tests --parallel - uv run ctest --test-dir .cache/cpp_tests --output-on-failure +unit_test_cpp: + $(MAKE) -C gigl-core unit_test_cpp unit_test: precondition_tests unit_test_py unit_test_scala unit_test_cpp @@ -122,12 +116,8 @@ check_format_md: @echo "Checking markdown files..." uv run mdformat --check ${MD_FILES} -# TODO: Remove the $(if ...) guards in check_format_cpp, format_cpp, check_lint_cpp, and -# fix_lint_cpp once C++ source files are permanently present in the repo. The guards exist -# to silently no-op on branches that have no python_*.cpp files yet; once there is always -# at least one C++ source, the guards just hide accidental empty-source mistakes. check_format_cpp: - $(if $(CPP_SOURCES),clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES)) + $(MAKE) -C gigl-core check_format_cpp # Checks formatting only (clang-format, black, scalafmt, mdformat). Does NOT run # clang-tidy static analysis — use `make check_lint_cpp` for that. @@ -165,22 +155,15 @@ format_md: uv run mdformat ${MD_FILES} format_cpp: - $(if $(CPP_SOURCES),clang-format-15 -i --style=file $(CPP_SOURCES)) + $(MAKE) -C gigl-core format_cpp format: format_py format_cpp format_scala format_md type_check: uv run mypy ${PYTHON_DIRS} --check-untyped-defs -# Stamp-file guard: uv pip install -e gigl-core/ triggers a full CMake configure-and-build -# cycle (loading torch headers) even when nothing changed. By making the stamp file -# depend on C++ sources and gigl-core/pyproject.toml, make skips the reinstall -# on subsequent runs unless something actually changed. The stamp file lives inside -# gigl-core/.cache/cmake_build so it is automatically invalidated if the build dir is cleaned. -gigl-core/.cache/cmake_build/CMakeInit.txt: $(shell find gigl-core/csrc \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) gigl-core/CMakeLists.txt gigl-core/pyproject.toml - uv pip install -e gigl-core/ - -build_cpp_extensions: gigl-core/.cache/cmake_build/CMakeInit.txt +build_cpp_extensions: + $(MAKE) -C gigl-core build_cpp_extensions check_lint_cpp: build_cpp_extensions $(if $(CPP_SOURCES_NO_CUDA),uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA)) @@ -198,7 +181,7 @@ lint_test: check_format assert_yaml_configs_parse check_lint_cpp # Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent # after switching between branches with substantially different CMakeLists.txt structure. clean_cpp: - rm -rf .cache/cpp_tests gigl-core/.cache/cmake_build + $(MAKE) -C gigl-core clean_cpp # compiles current working state of scala projects to local jars compile_jars: @@ -363,7 +346,7 @@ clean_build_files_scala: ( cd scala_spark35; sbt clean; find . -type d -name "target" -prune -exec rm -rf {} \; ) clean_build_files_cpp: - rm -rf .cache/cpp_tests + $(MAKE) -C gigl-core clean_build_files_cpp clean_build_files: clean_build_files_py clean_build_files_scala clean_build_files_cpp diff --git a/RELEASING.md b/RELEASING.md index 602253bee..95a46d5f6 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -8,7 +8,7 @@ GiGL is distributed as two wheels that are always installed together: - **`gigl-core`** — compiled C++/CUDA extensions, ABI-bound to the torch variant Both wheels are always versioned and released together. `bump_version.py` updates both versions and keeps the -`gigl-core` pin in `gigl/pyproject.toml` in sync automatically. +`gigl-core` pin in `pyproject.toml` in sync automatically. ## Release process diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 4e0aff48a..0a9e684ab 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -174,7 +174,7 @@ ______________________________________________________________________ ## pybind11 Extension Modules -Extension modules live under `gigl/csrc/`. +Extension modules live under `gigl-core/csrc/`. ### Naming convention @@ -184,11 +184,11 @@ Extension modules live under `gigl/csrc/`. | `.cpp` / `.cu` | Implementation — function and class definitions | | `.h` | Declarations (function signatures, class definitions, constants) | -Example: to add a `my_op` extension under `gigl/csrc/sampling/`: +Example: to add a `my_op` extension under `gigl-core/csrc/sampling/`: ``` -gigl/csrc/sampling/python_my_op.cpp ← pybind11 bindings -gigl/csrc/sampling/my_op.cpp ← implementation +gigl-core/csrc/sampling/python_my_op.cpp ← pybind11 bindings +gigl-core/csrc/sampling/my_op.cpp ← implementation ``` -The compiled `.so` is installed to the same directory and importable as `gigl.csrc.sampling.my_op`. +The compiled `.so` is installed into the `gigl_core` package and importable as `gigl_core.`. diff --git a/gigl-core/Makefile b/gigl-core/Makefile new file mode 100644 index 000000000..f3f63c7b8 --- /dev/null +++ b/gigl-core/Makefile @@ -0,0 +1,46 @@ +# C++ build, test, format, and clean targets for gigl-core. +# Invoked from the GiGL repo root via: $(MAKE) -C gigl-core +# All paths below are relative to gigl-core/. + +CPP_SOURCES := $(shell find csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) +# clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). +# Exclude .cu files from tidy targets; clang-format and clangd handle them fine. +CPP_SOURCES_NO_CUDA := $(filter-out %.cu,$(CPP_SOURCES)) + +# Stamp-file guard: uv pip install -e gigl-core/ triggers a full CMake configure-and-build +# cycle even when nothing changed. By making the stamp file depend on C++ sources and +# pyproject.toml, make skips the reinstall unless something actually changed. +# We cd to the repo root so that no-build-isolation-package in the root pyproject.toml +# is respected by uv pip install. +.cache/cmake_build/CMakeInit.txt: $(shell find csrc \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) CMakeLists.txt pyproject.toml + cd $(abspath $(CURDIR)/..) && uv pip install -e gigl-core/ + +build_cpp_extensions: .cache/cmake_build/CMakeInit.txt + +.cache/cpp_tests/.configured: CMakeLists.txt tests/CMakeLists.txt .cache/cmake_build/CMakeInit.txt + cmake -C .cache/cmake_build/CMakeInit.txt -S . -B .cache/cpp_tests -DGIGL_CORE_BUILD_TESTS=ON + touch .cache/cpp_tests/.configured + +unit_test_cpp: .cache/cpp_tests/.configured + cmake --build .cache/cpp_tests --parallel + ctest --test-dir .cache/cpp_tests --output-on-failure + +# TODO: Remove the $(if ...) guards once C++ source files are permanently present in the +# repo. The guards exist to silently no-op on branches that have no python_*.cpp files yet. +check_format_cpp: + $(if $(CPP_SOURCES),clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES)) + +format_cpp: + $(if $(CPP_SOURCES),clang-format-15 -i --style=file $(CPP_SOURCES)) + +# Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent +# after switching between branches with substantially different CMakeLists.txt structure. +clean_cpp: + rm -rf .cache/cpp_tests .cache/cmake_build + +clean_build_files_cpp: + rm -rf .cache/cpp_tests + +# Declare targets as phony so make always runs their recipes, even if a file or +# directory with the same name happens to exist on disk. +.PHONY: build_cpp_extensions unit_test_cpp check_format_cpp format_cpp clean_cpp clean_build_files_cpp diff --git a/requirements/install_cpp_deps.sh b/gigl-core/requirements/install_cpp_deps.sh similarity index 95% rename from requirements/install_cpp_deps.sh rename to gigl-core/requirements/install_cpp_deps.sh index 912bdee1a..497e4cb45 100644 --- a/requirements/install_cpp_deps.sh +++ b/gigl-core/requirements/install_cpp_deps.sh @@ -2,7 +2,7 @@ # Install C++ development tools: clang-format, clang-tidy, cmake. # # Usage: -# bash requirements/install_cpp_deps.sh +# bash gigl-core/requirements/install_cpp_deps.sh # # Called by `make install_dev_deps` alongside install_py_deps.sh and # install_scala_deps.sh. diff --git a/pyproject.toml b/pyproject.toml index 35a0cef35..ebbc65ea8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,9 +111,9 @@ no-build-isolation-package = ["gigl-core"] # scikit-build-core is gigl-core's PEP 517 build backend. With no-build-isolation-package # set, uv does not install [build-system].requires automatically, so it must be present # in the ambient environment before any gigl-core build (uv sync, uv build, Dockerfiles). -build-backend = ["scikit-build-core>=0.10"] +gigl-core-build-backend = ["scikit-build-core>=0.10"] dev = [ - {include-group = "build-backend"}, + {include-group = "gigl-core-build-backend"}, {include-group = "docs"}, {include-group = "lint"}, {include-group = "test"}, diff --git a/requirements/install_py_deps.sh b/requirements/install_py_deps.sh index edb9c700a..7b07b3095 100644 --- a/requirements/install_py_deps.sh +++ b/requirements/install_py_deps.sh @@ -143,7 +143,7 @@ install_gigl_lib_deps() { # https://docs.astral.sh/uv/reference/cli/#uv-sync uv sync ${extra_deps_clause[@]} --group dev --locked ${flag_use_inexact_match} else - uv sync ${extra_deps_clause[@]} --group build-backend --locked ${flag_use_inexact_match} + uv sync ${extra_deps_clause[@]} --group gigl-core-build-backend --locked ${flag_use_inexact_match} fi # Taken from https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script From b598f3d72eee47f5513dcb39460944459a0a012f Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 27 Apr 2026 23:22:00 +0000 Subject: [PATCH 123/148] update uv lock --- uv.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uv.lock b/uv.lock index 8774acac8..b8303f693 100644 --- a/uv.lock +++ b/uv.lock @@ -769,9 +769,6 @@ transform = [ ] [package.dev-dependencies] -build-backend = [ - { name = "scikit-build-core" }, -] dev = [ { name = "astroid" }, { name = "mdformat" }, @@ -820,6 +817,9 @@ docs = [ { name = "sphinx-rtd-theme" }, { name = "sphinx-tabs" }, ] +gigl-core-build-backend = [ + { name = "scikit-build-core" }, +] lint = [ { name = "mdformat" }, { name = "mdformat-tables" }, @@ -895,7 +895,6 @@ requires-dist = [ provides-extras = ["transform", "pyg27-torch28-cpu", "pyg27-torch28-cu128", "experimental"] [package.metadata.requires-dev] -build-backend = [{ name = "scikit-build-core", specifier = ">=0.10" }] dev = [ { name = "astroid", specifier = "==3.3.11" }, { name = "mdformat", specifier = "==0.7.22" }, @@ -944,6 +943,7 @@ docs = [ { name = "sphinx-rtd-theme", specifier = "==2.0.0" }, { name = "sphinx-tabs", specifier = "==3.4.5" }, ] +gigl-core-build-backend = [{ name = "scikit-build-core", specifier = ">=0.10" }] lint = [ { name = "mdformat", specifier = "==0.7.22" }, { name = "mdformat-tables", specifier = "==1.0.0" }, From a482bed597e797bf7cf449cde5bfb519765b5178 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 27 Apr 2026 23:32:10 +0000 Subject: [PATCH 124/148] [AUTOMATED] Update dep.vars, and other relevant files with new image names --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- gigl/dep_vars.env | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index c93ccf8b0..d99c024a3 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 entrypoint: /bin/bash args: - -c diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index ef0f137a8..4b28e38b7 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:525f8fccccec71daf2381ea1ab4d7891c449c0ef.106.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 From f40e94e725d9405a7304b52e50e3a1594558f9de Mon Sep 17 00:00:00 2001 From: mkolodner Date: Tue, 28 Apr 2026 20:14:04 +0000 Subject: [PATCH 125/148] Address comments --- .github/workflows/release.yml | 6 +++--- gigl-core/uv.lock | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 gigl-core/uv.lock diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8370cbd26..3325d1c98 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,6 @@ permissions: jobs: build: name: Build and release pip whl (${{ matrix.torch-variant }}) - runs-on: ${{ matrix.runner }} strategy: matrix: include: @@ -23,6 +22,7 @@ jobs: - runner: gigl-gpu-instances torch-variant: cu128 publish-url: https://us-central1-python.pkg.dev/external-snap-ci-github-gigl/gigl-cu128 + runs-on: ${{ matrix.runner }} env: PROJECT_ID: ${{ vars.GCP_PROJECT_ID }} environment: @@ -59,7 +59,7 @@ jobs: run: | # Remove stale cmake cache from previous runs on self-hosted runners. rm -rf gigl-core/.cache/cmake_build - uv build --wheel gigl-core/ + uv build --wheel gigl-core/ --locked - name: Publish gigl-core wheel working-directory: gigl-core @@ -73,5 +73,5 @@ jobs: # when gigl becomes available. - name: Build and publish gigl wheel run: | - uv build --wheel + uv build --wheel --locked uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess diff --git a/gigl-core/uv.lock b/gigl-core/uv.lock new file mode 100644 index 000000000..83b24499e --- /dev/null +++ b/gigl-core/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 3 +requires-python = "==3.11.*" + +[[package]] +name = "gigl-core" +version = "0.2.0" +source = { editable = "." } From a5ace2fd246cc2a41f906e2b92c6321900c75c41 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 18:30:57 +0000 Subject: [PATCH 126/148] Add tests --- gigl-core/tests/CMakeLists.txt | 18 +++- gigl-core/tests/ppr_forward_push_test.cpp | 116 ++++++++++++++++++++++ gigl/csrc/sampling/__init__.py | 3 - gigl/distributed/dist_ppr_sampler.py | 2 +- 4 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 gigl-core/tests/ppr_forward_push_test.cpp delete mode 100644 gigl/csrc/sampling/__init__.py diff --git a/gigl-core/tests/CMakeLists.txt b/gigl-core/tests/CMakeLists.txt index 74eac1f40..b93af3bb8 100644 --- a/gigl-core/tests/CMakeLists.txt +++ b/gigl-core/tests/CMakeLists.txt @@ -24,6 +24,22 @@ FetchContent_MakeAvailable(googletest) # Required for add_test() to register tests with CTest. enable_testing() +# --------------------------------------------------------------------------- +# Torch + sampling kernel (required by PPR tests) +# --------------------------------------------------------------------------- +foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) + if(NOT TORCH_CMAKE_PREFIX AND EXISTS "${_prefix}/torch/share/cmake") + set(TORCH_CMAKE_PREFIX "${_prefix}/torch/share/cmake") + endif() +endforeach() +find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") + +add_library(gigl_core_sampling STATIC + "${CMAKE_CURRENT_SOURCE_DIR}/../csrc/sampling/ppr_forward_push.cpp" +) +target_include_directories(gigl_core_sampling PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../csrc") +target_link_libraries(gigl_core_sampling PUBLIC "${TORCH_LIBRARIES}") + # --------------------------------------------------------------------------- # Auto-discover test targets # --------------------------------------------------------------------------- @@ -45,7 +61,7 @@ foreach(test_source ${TEST_SOURCES}) string(REPLACE "/" "_" test_name "${_rel}") string(REGEX REPLACE "\\.[^.]+$" "" test_name "${test_name}") add_executable(${test_name} ${test_source}) - target_link_libraries(${test_name} GTest::gtest_main) + target_link_libraries(${test_name} GTest::gtest_main gigl_core_sampling) # add_test registers the binary with CTest. Each *_test binary is one # CTest entry; GoogleTest itself reports individual TEST() results inside it. add_test(NAME ${test_name} COMMAND ${test_name}) diff --git a/gigl-core/tests/ppr_forward_push_test.cpp b/gigl-core/tests/ppr_forward_push_test.cpp new file mode 100644 index 000000000..2203e3032 --- /dev/null +++ b/gigl-core/tests/ppr_forward_push_test.cpp @@ -0,0 +1,116 @@ +#include +#include "sampling/ppr_forward_push.h" + +// Builds a single-edge-type, single-node-type PPRForwardPushState. +static PPRForwardPushState makeState( + std::vector seeds, + double alpha, + double requeueThresholdFactor, + std::vector degrees) { + return PPRForwardPushState( + torch::tensor(seeds, torch::kLong), + /*seedNodeTypeId=*/0, + alpha, + requeueThresholdFactor, + /*nodeTypeToEdgeTypeIds=*/{{0}}, + /*edgeTypeToDstNtypeId=*/{0}, + {torch::tensor(degrees, torch::kInt)}); +} + +// After construction, drainQueue() returns the seed node under etype 0. +TEST(PPRForwardPush, DrainQueueReturnsSeedNodeInitially) { + auto state = makeState({0}, 0.15, 1e-6, {1}); + auto result = state.drainQueue(); + ASSERT_TRUE(result.has_value()); + ASSERT_NE(result->find(0), result->end()); + EXPECT_EQ(result->at(0).size(0), 1); + EXPECT_EQ(result->at(0)[0].item(), 0); +} + +// After convergence (sink node absorbs all residual), drainQueue() returns nullopt. +TEST(PPRForwardPush, DrainQueueReturnsNulloptAfterConvergence) { + auto state = makeState({0}, 0.15, 1e-6, {0}); // node 0 is a sink (degree 0) + state.drainQueue(); + state.pushResiduals({}); + EXPECT_FALSE(state.drainQueue().has_value()); +} + +// A sink seed node absorbs its full residual as PPR score (= alpha). +TEST(PPRForwardPush, PprScoreAbsorbsAlpha) { + const double alpha = 0.15; + auto state = makeState({0}, alpha, 1e-6, {0}); + state.drainQueue(); + state.pushResiduals({}); + auto topk = state.extractTopK(10); + ASSERT_NE(topk.find(0), topk.end()); + const auto& [ids, weights, counts] = topk.at(0); + EXPECT_EQ(ids[0].item(), 0); + EXPECT_NEAR(weights[0].item(), static_cast(alpha), 1e-5f); +} + +// Node 0 (degree 1) pushes (1-alpha)*alpha residual to node 1 (sink). +TEST(PPRForwardPush, ResidualDistributedToNeighbor) { + const double alpha = 0.15; + auto state = makeState({0}, alpha, 1e-6, {1, 0}); + + // Iteration 1: seed node 0 → neighbor node 1. + state.drainQueue(); + state.pushResiduals({{0, + {torch::tensor(std::vector{0}, torch::kLong), + torch::tensor(std::vector{1}, torch::kLong), + torch::tensor(std::vector{1}, torch::kLong)}}}); + + // Iteration 2: node 1 is a sink; absorbs its residual, no further push. + state.drainQueue(); + state.pushResiduals({}); + + EXPECT_FALSE(state.drainQueue().has_value()); + + auto topk = state.extractTopK(10); + ASSERT_NE(topk.find(0), topk.end()); + const auto& [ids, weights, counts] = topk.at(0); + ASSERT_EQ(counts[0].item(), 2); + EXPECT_EQ(ids[0].item(), 0); + EXPECT_EQ(ids[1].item(), 1); + EXPECT_NEAR(weights[0].item(), static_cast(alpha), 1e-5f); + EXPECT_NEAR(weights[1].item(), static_cast((1.0 - alpha) * alpha), 1e-5f); +} + +// Two seeds both push residual to node 2; the neighbor-lookup request deduplicates +// to one entry, but getNodesDrainedPerIteration counts both seed queues. +TEST(PPRForwardPush, DeduplicatesNodesAcrossSeeds) { + auto state = makeState({0, 1}, 0.15, 1e-6, {1, 1, 0}); + + state.drainQueue(); + state.pushResiduals({{0, + {torch::tensor(std::vector{0, 1}, torch::kLong), + torch::tensor(std::vector{2, 2}, torch::kLong), + torch::tensor(std::vector{1, 1}, torch::kLong)}}}); + + auto iter2 = state.drainQueue(); + ASSERT_TRUE(iter2.has_value()); + ASSERT_NE(iter2->find(0), iter2->end()); + EXPECT_EQ(iter2->at(0).size(0), 1); // node 2 deduplicated in lookup + EXPECT_EQ(state.getNodesDrainedPerIteration()[1], 2); // but drained from 2 seed queues +} + +// extractTopK respects the maxPprNodes limit. +TEST(PPRForwardPush, ExtractTopKLimitsResults) { + auto state = makeState({0}, 0.15, 1e-6, {1, 0}); + + state.drainQueue(); + state.pushResiduals({{0, + {torch::tensor(std::vector{0}, torch::kLong), + torch::tensor(std::vector{1}, torch::kLong), + torch::tensor(std::vector{1}, torch::kLong)}}}); + state.drainQueue(); + state.pushResiduals({}); + + auto topk1 = state.extractTopK(1); + ASSERT_NE(topk1.find(0), topk1.end()); + EXPECT_EQ(std::get<2>(topk1.at(0))[0].item(), 1); + + auto topk10 = state.extractTopK(10); + ASSERT_NE(topk10.find(0), topk10.end()); + EXPECT_EQ(std::get<2>(topk10.at(0))[0].item(), 2); +} diff --git a/gigl/csrc/sampling/__init__.py b/gigl/csrc/sampling/__init__.py deleted file mode 100644 index 5e307b635..000000000 --- a/gigl/csrc/sampling/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from gigl_core import PPRForwardPushState - -__all__ = ["PPRForwardPushState"] diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 0e4290c58..cbf514acf 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -4,6 +4,7 @@ from typing import Optional, Union import torch +from gigl_core import PPRForwardPushState from graphlearn_torch.sampler import ( HeteroSamplerOutput, NeighborOutput, @@ -14,7 +15,6 @@ from graphlearn_torch.utils import merge_dict from gigl.common.logger import Logger -from gigl.csrc.sampling import PPRForwardPushState from gigl.distributed.base_sampler import BaseDistNeighborSampler from gigl.types.graph import is_label_edge_type From 97d9cbb35459fdefc18698b37c72a03753b804d1 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 18:37:09 +0000 Subject: [PATCH 127/148] Update --- gigl-core/tests/CMakeLists.txt | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/gigl-core/tests/CMakeLists.txt b/gigl-core/tests/CMakeLists.txt index b93af3bb8..a37aedf7f 100644 --- a/gigl-core/tests/CMakeLists.txt +++ b/gigl-core/tests/CMakeLists.txt @@ -25,7 +25,7 @@ FetchContent_MakeAvailable(googletest) enable_testing() # --------------------------------------------------------------------------- -# Torch + sampling kernel (required by PPR tests) +# Torch + kernel library (required by tests that use C++ kernels) # --------------------------------------------------------------------------- foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) if(NOT TORCH_CMAKE_PREFIX AND EXISTS "${_prefix}/torch/share/cmake") @@ -34,11 +34,18 @@ foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) endforeach() find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") -add_library(gigl_core_sampling STATIC - "${CMAKE_CURRENT_SOURCE_DIR}/../csrc/sampling/ppr_forward_push.cpp" -) -target_include_directories(gigl_core_sampling PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../csrc") -target_link_libraries(gigl_core_sampling PUBLIC "${TORCH_LIBRARIES}") +# Auto-discover all kernel sources under csrc/. python_*.cpp are pybind11 +# extension entry points that belong to the wheel, not to the test library. +if(CMAKE_CUDA_COMPILER) + file(GLOB_RECURSE _KERNEL_SRCS "${CMAKE_SOURCE_DIR}/csrc/*.cpp" "${CMAKE_SOURCE_DIR}/csrc/*.cu") +else() + file(GLOB_RECURSE _KERNEL_SRCS "${CMAKE_SOURCE_DIR}/csrc/*.cpp") +endif() +list(FILTER _KERNEL_SRCS EXCLUDE REGEX ".*/python_[^/]*$") + +add_library(gigl_core_kernels STATIC ${_KERNEL_SRCS}) +target_include_directories(gigl_core_kernels PUBLIC "${CMAKE_SOURCE_DIR}/csrc") +target_link_libraries(gigl_core_kernels PUBLIC "${TORCH_LIBRARIES}") # --------------------------------------------------------------------------- # Auto-discover test targets @@ -61,7 +68,7 @@ foreach(test_source ${TEST_SOURCES}) string(REPLACE "/" "_" test_name "${_rel}") string(REGEX REPLACE "\\.[^.]+$" "" test_name "${test_name}") add_executable(${test_name} ${test_source}) - target_link_libraries(${test_name} GTest::gtest_main gigl_core_sampling) + target_link_libraries(${test_name} GTest::gtest_main gigl_core_kernels) # add_test registers the binary with CTest. Each *_test binary is one # CTest entry; GoogleTest itself reports individual TEST() results inside it. add_test(NAME ${test_name} COMMAND ${test_name}) From efeaf1dc2ceba2c05223be4992e7ca32fb4ba80e Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 19:01:09 +0000 Subject: [PATCH 128/148] Update --- gigl-core/csrc/sampling/ppr_forward_push.cpp | 2 +- gigl/distributed/dist_ppr_sampler.py | 144 +------------------ gigl/distributed/sampler_options.py | 10 +- gigl/distributed/utils/neighborloader.py | 2 + 4 files changed, 15 insertions(+), 143 deletions(-) diff --git a/gigl-core/csrc/sampling/ppr_forward_push.cpp b/gigl-core/csrc/sampling/ppr_forward_push.cpp index f97b2f40c..daf4f1c2b 100644 --- a/gigl-core/csrc/sampling/ppr_forward_push.cpp +++ b/gigl-core/csrc/sampling/ppr_forward_push.cpp @@ -274,7 +274,7 @@ int32_t PPRForwardPushState::getTotalDegree(int32_t nodeId, int32_t ntypeId) con if (t.numel() == 0) { return 0; } - TORCH_CHECK(nodeId < static_cast(t.size(0)), + TORCH_CHECK(nodeId >= 0 && nodeId < static_cast(t.size(0)), "Node ID ", nodeId, " out of range for degree tensor of ntype_id ", diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index cbf514acf..74ec80a6d 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -1,5 +1,4 @@ import asyncio -import time from collections import defaultdict from typing import Optional, Union @@ -26,13 +25,6 @@ # yield a bare EdgeType repr for ast.literal_eval). PPR_EDGE_INDEX_METADATA_KEY = "ppr_edge_index." PPR_WEIGHT_METADATA_KEY = "ppr_weight." -PPR_FETCH_TIME_MS_METADATA_KEY = "ppr_fetch_time_ms" -PPR_PUSH_TIME_MS_METADATA_KEY = "ppr_push_time_ms" -PPR_ITERATIONS_METADATA_KEY = "ppr_iterations" -PPR_NODES_PER_ITERATION_METADATA_KEY = "ppr_nodes_per_iteration" -PPR_FETCH_TIME_PER_ITER_MS_METADATA_KEY = "ppr_fetch_time_per_iter_ms" -PPR_PUSH_TIME_PER_ITER_MS_METADATA_KEY = "ppr_push_time_per_iter_ms" -PPR_NODES_NEEDING_FETCH_PER_ITER_METADATA_KEY = "ppr_nodes_needing_fetch_per_iter" # Sentinel type names for homogeneous graphs. The PPR algorithm uses # dict[NodeType, ...] internally for both homo and hetero graphs; these @@ -102,7 +94,7 @@ def __init__( num_neighbors_per_hop: int = 100_000, total_degree_dtype: torch.dtype = torch.int32, degree_tensors: Union[torch.Tensor, dict[EdgeType, torch.Tensor]], - max_fetch_iterations: int = 0, + max_fetch_iterations: Optional[int] = None, **kwargs, ): super().__init__(*args, **kwargs) @@ -331,7 +323,6 @@ async def _compute_ppr_scores( Union[torch.Tensor, dict[NodeType, torch.Tensor]], Union[torch.Tensor, dict[NodeType, torch.Tensor]], Union[torch.Tensor, dict[NodeType, torch.Tensor]], - tuple[float, float, int, list[int], list[float], list[float], list[int]], ]: """ Compute PPR scores for seed nodes using the push-based approximation algorithm. @@ -373,9 +364,6 @@ async def _compute_ppr_scores( seed, shape ``[batch_size]``. Used to slice the flat tensors into per-seed groups: seed ``i``'s neighbors are at ``flat_neighbor_ids[sum(valid_counts[:i]) : sum(valid_counts[:i+1])]``. - - timing: ``(fetch_ms, push_ms, iterations)`` — wall-clock time - spent in neighbor fetch (ms), residual push (ms), and total loop - iteration count for this call. Example:: @@ -398,13 +386,7 @@ async def _compute_ppr_scores( self._degree_tensors_for_cpp, ) - total_fetch_ms = 0.0 - total_push_ms = 0.0 - total_iterations = 0 fetch_iteration_count = 0 - fetch_ms_per_iter: list[float] = [] - push_ms_per_iter: list[float] = [] - nodes_needing_fetch_per_iter: list[int] = [] while True: # drain_queue returns None when the queue is truly empty (convergence), @@ -412,44 +394,27 @@ async def _compute_ppr_scores( # means all drained nodes either had cached neighbors or no outgoing # edges — we still call push_residuals to flush their residuals into # ppr_scores_. - drain_result: Optional[dict[int, torch.Tensor]] = ppr_state.drain_queue() - if drain_result is None: + nodes_by_etype_id = ppr_state.drain_queue() + if nodes_by_etype_id is None: break - nodes_by_etype_id: dict[int, torch.Tensor] = drain_result fetch_budget_remaining = ( - self._max_fetch_iterations == 0 + self._max_fetch_iterations is None or fetch_iteration_count < self._max_fetch_iterations ) if nodes_by_etype_id and fetch_budget_remaining: - # Total (node, edge_type) pairs needing RPCs this iteration. - # A node with uncached neighbors for k edge types contributes k here. - nodes_needing_fetch = sum(t.numel() for t in nodes_by_etype_id.values()) - fetch_start = time.perf_counter() fetched_by_etype_id = await self._batch_fetch_neighbors( nodes_by_etype_id, device ) - iter_fetch_ms = (time.perf_counter() - fetch_start) * 1000 - total_fetch_ms += iter_fetch_ms fetch_iteration_count += 1 else: - # Either all nodes are cached, or the fetch budget is exhausted. - # push_residuals will propagate using the existing neighbor cache. - nodes_needing_fetch = 0 + # Fetch budget exhausted; push_residuals will use the existing neighbor cache. fetched_by_etype_id = {} - iter_fetch_ms = 0.0 - nodes_needing_fetch_per_iter.append(nodes_needing_fetch) - fetch_ms_per_iter.append(iter_fetch_ms) - - push_start = time.perf_counter() + # Run in executor so the C++ push doesn't block the asyncio event loop. await asyncio.get_running_loop().run_in_executor( None, ppr_state.push_residuals, fetched_by_etype_id ) - iter_push_ms = (time.perf_counter() - push_start) * 1000 - total_push_ms += iter_push_ms - push_ms_per_iter.append(iter_push_ms) - total_iterations += 1 # Translate ntype_id integer keys back to NodeType strings for the rest # of the pipeline, and move tensors to the correct device. @@ -465,18 +430,6 @@ async def _compute_ppr_scores( ntype_to_flat_weights[ntype] = flat_weights.to(device) ntype_to_valid_counts[ntype] = valid_counts.to(device) - nodes_drained_per_iteration: list[int] = ( - ppr_state.get_nodes_drained_per_iteration() - ) - timing = ( - total_fetch_ms, - total_push_ms, - total_iterations, - nodes_drained_per_iteration, - fetch_ms_per_iter, - push_ms_per_iter, - nodes_needing_fetch_per_iter, - ) if self._is_homogeneous: assert ( len(ntype_to_flat_ids) == 1 @@ -486,14 +439,12 @@ async def _compute_ppr_scores( ntype_to_flat_ids[_PPR_HOMOGENEOUS_NODE_TYPE], ntype_to_flat_weights[_PPR_HOMOGENEOUS_NODE_TYPE], ntype_to_valid_counts[_PPR_HOMOGENEOUS_NODE_TYPE], - timing, ) else: return ( ntype_to_flat_ids, ntype_to_flat_weights, ntype_to_valid_counts, - timing, ) async def _sample_from_nodes( @@ -604,51 +555,12 @@ async def _sample_from_nodes( nbr_dict: dict[EdgeType, list[torch.Tensor]] = {} ppr_edge_type_to_flat_weights: dict[EdgeType, torch.Tensor] = {} - total_fetch_ms = 0.0 - total_push_ms = 0.0 - total_iterations = 0 - total_nodes_per_iteration: list[int] = [] - total_fetch_ms_per_iter: list[float] = [] - total_push_ms_per_iter: list[float] = [] - total_nodes_needing_fetch_per_iter: list[int] = [] for seed_type, ( ntype_to_flat_ids, ntype_to_flat_weights, ntype_to_valid_counts, - ( - fetch_ms, - push_ms, - iterations, - nodes_per_iter, - fetch_ms_per_iter, - push_ms_per_iter, - nodes_needing_fetch_per_iter, - ), ) in zip(seed_types, ppr_results): - total_fetch_ms += fetch_ms - total_push_ms += push_ms - total_iterations += iterations - for i, count in enumerate(nodes_per_iter): - if i < len(total_nodes_per_iteration): - total_nodes_per_iteration[i] += count - else: - total_nodes_per_iteration.append(count) - for i, val in enumerate(fetch_ms_per_iter): - if i < len(total_fetch_ms_per_iter): - total_fetch_ms_per_iter[i] += val - else: - total_fetch_ms_per_iter.append(val) - for i, val in enumerate(push_ms_per_iter): - if i < len(total_push_ms_per_iter): - total_push_ms_per_iter[i] += val - else: - total_push_ms_per_iter.append(val) - for i, val in enumerate(nodes_needing_fetch_per_iter): - if i < len(total_nodes_needing_fetch_per_iter): - total_nodes_needing_fetch_per_iter[i] += val - else: - total_nodes_needing_fetch_per_iter.append(val) assert isinstance(ntype_to_flat_ids, dict) assert isinstance(ntype_to_flat_weights, dict) assert isinstance(ntype_to_valid_counts, dict) @@ -713,24 +625,6 @@ async def _sample_from_nodes( metadata[f"{PPR_EDGE_INDEX_METADATA_KEY}{etype_str}"] = edge_index metadata[f"{PPR_WEIGHT_METADATA_KEY}{etype_str}"] = flat_weights - metadata[PPR_FETCH_TIME_MS_METADATA_KEY] = torch.tensor(total_fetch_ms) - metadata[PPR_PUSH_TIME_MS_METADATA_KEY] = torch.tensor(total_push_ms) - metadata[PPR_ITERATIONS_METADATA_KEY] = torch.tensor( - total_iterations, dtype=torch.long - ) - metadata[PPR_NODES_PER_ITERATION_METADATA_KEY] = torch.tensor( - total_nodes_per_iteration, dtype=torch.long - ) - metadata[PPR_FETCH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( - total_fetch_ms_per_iter, dtype=torch.float - ) - metadata[PPR_PUSH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( - total_push_ms_per_iter, dtype=torch.float - ) - metadata[PPR_NODES_NEEDING_FETCH_PER_ITER_METADATA_KEY] = torch.tensor( - total_nodes_needing_fetch_per_iter, dtype=torch.long - ) - sample_output = HeteroSamplerOutput( node=node_dict, # row/col/edge are left empty rather than populated with PPR edges because @@ -761,15 +655,6 @@ async def _sample_from_nodes( homo_flat_ids, homo_flat_weights, homo_valid_counts, - ( - total_fetch_ms, - total_push_ms, - total_iterations, - total_nodes_per_iteration, - total_fetch_ms_per_iter, - total_push_ms_per_iter, - total_nodes_needing_fetch_per_iter, - ), ) = await self._compute_ppr_scores(nodes_to_sample, None) assert isinstance(homo_flat_ids, torch.Tensor) assert isinstance(homo_flat_weights, torch.Tensor) @@ -791,23 +676,6 @@ async def _sample_from_nodes( metadata["edge_index"] = ppr_edge_index metadata["edge_attr"] = homo_flat_weights - metadata[PPR_FETCH_TIME_MS_METADATA_KEY] = torch.tensor(total_fetch_ms) - metadata[PPR_PUSH_TIME_MS_METADATA_KEY] = torch.tensor(total_push_ms) - metadata[PPR_ITERATIONS_METADATA_KEY] = torch.tensor( - total_iterations, dtype=torch.long - ) - metadata[PPR_NODES_PER_ITERATION_METADATA_KEY] = torch.tensor( - total_nodes_per_iteration, dtype=torch.long - ) - metadata[PPR_FETCH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( - total_fetch_ms_per_iter, dtype=torch.float - ) - metadata[PPR_PUSH_TIME_PER_ITER_MS_METADATA_KEY] = torch.tensor( - total_push_ms_per_iter, dtype=torch.float - ) - metadata[PPR_NODES_NEEDING_FETCH_PER_ITER_METADATA_KEY] = torch.tensor( - total_nodes_needing_fetch_per_iter, dtype=torch.long - ) sample_output = SamplerOutput( node=all_nodes, diff --git a/gigl/distributed/sampler_options.py b/gigl/distributed/sampler_options.py index d72c9092e..fccd7a3ba 100644 --- a/gigl/distributed/sampler_options.py +++ b/gigl/distributed/sampler_options.py @@ -54,8 +54,10 @@ class PPRSamplerOptions: max_ppr_nodes: Maximum number of nodes to return per seed based on PPR scores. num_neighbors_per_hop: Maximum number of neighbors fetched per node per edge - type during PPR traversal. Set large to approximate fetching all - neighbors. + type during PPR traversal. 1000 is sufficient in practice — high-degree + hub nodes receive diminishing residual per neighbor, so capping the fetch + has little effect on PPR accuracy while keeping per-hop RPC cost bounded. + Set large to approximate fetching all neighbors. total_degree_dtype: Dtype for precomputed total-degree tensors. Defaults to ``torch.int32``, which supports total degrees up to ~2 billion. Use a larger dtype if nodes have exceptionally high aggregate degrees. @@ -63,7 +65,7 @@ class PPRSamplerOptions: fetches. After this many fetch iterations, subsequent iterations push residuals using only already-cached neighbor lists (no new RPCs). The algorithm still runs to convergence — re-enqueued nodes propagate - through cached neighbors at negligible cost. Set to 0 (default) for + through cached neighbors at negligible cost. ``None`` (default) means no fetch limit. """ @@ -72,7 +74,7 @@ class PPRSamplerOptions: max_ppr_nodes: int = 50 num_neighbors_per_hop: int = 1_000 total_degree_dtype: torch.dtype = torch.int32 - max_fetch_iterations: int = 0 + max_fetch_iterations: Optional[int] = None SamplerOptions = Union[KHopNeighborSamplerOptions, PPRSamplerOptions] diff --git a/gigl/distributed/utils/neighborloader.py b/gigl/distributed/utils/neighborloader.py index 004cd6d6b..8ea4c86f4 100644 --- a/gigl/distributed/utils/neighborloader.py +++ b/gigl/distributed/utils/neighborloader.py @@ -190,6 +190,8 @@ def strip_non_ppr_edge_types( for edge_type in list(data.edge_types): if edge_type not in ppr_edge_types: del data[edge_type] + # GLT does not guarantee an entry in num_sampled_edges for every edge type + # (e.g. types with zero samples may be absent), so use pop instead of del. data.num_sampled_edges.pop(edge_type, None) return data From 37e967efa5ae56da5ebbda0f2ae6638513b9f887 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 19:05:43 +0000 Subject: [PATCH 129/148] Update --- gigl-core/src/gigl_core/py.typed | 0 gigl/distributed/dist_sampling_producer.py | 1 - 2 files changed, 1 deletion(-) delete mode 100644 gigl-core/src/gigl_core/py.typed diff --git a/gigl-core/src/gigl_core/py.typed b/gigl-core/src/gigl_core/py.typed deleted file mode 100644 index e69de29bb..000000000 diff --git a/gigl/distributed/dist_sampling_producer.py b/gigl/distributed/dist_sampling_producer.py index 9c4624da8..3a51715e2 100644 --- a/gigl/distributed/dist_sampling_producer.py +++ b/gigl/distributed/dist_sampling_producer.py @@ -104,7 +104,6 @@ def _sampling_worker_loop( degree_tensors=degree_tensors, current_device=current_device, ) - dist_sampler.start_loop() unshuffled_index_loader: Optional[DataLoader] From bd3bd13543ad81d10cf05a0a0d3e542aabccde08 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 20:29:08 +0000 Subject: [PATCH 130/148] Update --- gigl-core/csrc/sampling/ppr_forward_push.h | 117 ++++++--------------- 1 file changed, 34 insertions(+), 83 deletions(-) diff --git a/gigl-core/csrc/sampling/ppr_forward_push.h b/gigl-core/csrc/sampling/ppr_forward_push.h index 7a6fac69d..ac7366ee5 100644 --- a/gigl-core/csrc/sampling/ppr_forward_push.h +++ b/gigl-core/csrc/sampling/ppr_forward_push.h @@ -2,47 +2,31 @@ #include -#include // std::partial_sort, std::min -#include // Fixed-width integer types: int32_t, int64_t, uint32_t, uint64_t -#include // std::optional for nullable return values -#include // std::tuple for multi-value returns -#include // std::unordered_map — like Python dict, O(1) average lookup -#include // std::unordered_set — like Python set, O(1) average lookup -#include // std::vector — like Python list, contiguous in memory +#include +#include +#include +#include +#include +#include +#include -// Combine (node_id, etype_id) into a single 64-bit integer for use as a hash -// map key. A single 64-bit integer is cheaper to hash than a pair of two -// integers (std::unordered_map has no built-in pair hash). -// -// Bit layout: -// bits 63–32: node_id (upper half) -// bits 31– 0: etype_id (lower half) -// -// Both inputs are cast through uint32_t before packing. Without this, a -// negative int32_t (e.g. -1 = 0xFFFFFFFF) would be sign-extended to a full -// 64-bit value, corrupting the upper bits when shifted. Reinterpreting as -// uint32_t first treats the bit pattern as-is (no sign extension). +// Pack (node_id, etype_id) into a single uint64 for use as a hash key. +// Inputs are cast through uint32_t to avoid sign-extension of negative int32 values. static inline uint64_t packKey(int32_t nodeId, int32_t etypeId) { return (static_cast(static_cast(nodeId)) << 32) | static_cast(etypeId); } -// C++ kernel for the PPR Forward Push algorithm (Andersen et al., 2006). -// -// All hot-loop state (scores, residuals, queue, neighbor cache) lives inside -// this object. The distributed neighbor fetch is kept in Python because it -// involves async RPC calls that C++ cannot drive directly. +// C++ kernel for PPR Forward Push (Andersen et al., 2006). +// Hot-loop state lives here; distributed neighbor fetches are driven from Python. // -// Owned state: _pprScores, _residuals, _queue, _queuedNodes, _neighborCache. -// Python retains ownership of: the distributed neighbor fetch (_batch_fetch_neighbors). -// -// Typical call sequence per batch: -// 1. PPRForwardPushState(seedNodes, ...) — init per-seed residuals / queue +// Call sequence per batch: +// 1. PPRForwardPushState(seedNodes, ...) // while True: -// 2. drainQueue() — drain queue → nodes needing lookup -// 3. — distributed RPC fetch (stays in Python) -// 4. pushResiduals(fetchedByEtypeId) — push residuals, update queue -// 5. extractTopK(maxPprNodes) — top-k selection per seed per node type +// 2. drainQueue() → nodes needing neighbor lookup +// 3. +// 4. pushResiduals(fetchedByEtypeId) +// 5. extractTopK(maxPprNodes) class PPRForwardPushState { public: PPRForwardPushState(const torch::Tensor& seedNodes, @@ -53,81 +37,48 @@ class PPRForwardPushState { std::vector edgeTypeToDstNtypeId, std::vector degreeTensors); - // Drain all queued nodes and return {etype_id: tensor[node_ids]} for batch - // neighbor lookup. Also snapshots the drained nodes into _queuedNodes for - // use by pushResiduals(). - // - // Return value semantics: - // - std::nullopt → queue was already empty; convergence achieved; stop the loop. - // - empty map → nodes were drained but all were cached; call pushResiduals({}). - // - non-empty map → {etype_id → 1-D int64 tensor of node IDs} needing neighbor lookup. + // Drain queued nodes and return {etype_id: int64 node tensor} for neighbor lookup. + // Returns nullopt when the queue is empty (convergence). Empty map means all nodes + // were cache-hits; call pushResiduals({}) to continue. std::optional> drainQueue(); - // Push residuals to neighbors given the fetched neighbor data. - // - // fetchedByEtypeId: {etype_id: (node_ids_tensor, flat_nbrs_tensor, counts_tensor)} - // - node_ids_tensor: [N] int64 — source node IDs fetched for this edge type - // - flat_nbrs_tensor: [sum(counts)] int64 — all neighbor lists concatenated flat - // - counts_tensor: [N] int64 — neighbor count for each source node + // Push residuals given fetched neighbor data. + // fetchedByEtypeId: {etype_id: (node_ids[N], flat_nbrs[sum(counts)], counts[N])} void pushResiduals(const std::unordered_map< int32_t, std::tuple>& fetchedByEtypeId); - // Extract top-k PPR nodes per seed per node type. - // - // Returns {ntype_id: (flat_ids_tensor, flat_weights_tensor, valid_counts_tensor)}. - // Only node types that received any PPR score are included in the output. - // - // Output layout for a batch of B seeds: - // flat_ids[0 : valid_counts[0]] → top-k nodes for seed 0 - // flat_ids[valid_counts[0] : valid_counts[0]+valid_counts[1]] → top-k for seed 1 - // ... + // Return top-k PPR nodes per seed per node type. + // Result: {ntype_id: (flat_ids, flat_weights, valid_counts)} — one entry per active ntype. std::unordered_map> extractTopK(int32_t maxPprNodes); - // Returns _nodesDrainedPerIteration built up across all drainQueue() calls. + // Total nodes drained per drainQueue() call, across all seeds and node types. [[nodiscard]] const std::vector& getNodesDrainedPerIteration() const; private: - // Look up the total (across all edge types) out-degree of a node. - // Returns 0 for destination-only node types (no outgoing edges). + // Total out-degree of a node across all edge types. Returns 0 for sink nodes. [[nodiscard]] int32_t getTotalDegree(int32_t nodeId, int32_t ntypeId) const; - // ------------------------------------------------------------------------- - // Scalar algorithm parameters - // ------------------------------------------------------------------------- - double _alpha; // Restart probability - double _oneMinusAlpha; // 1 - alpha, precomputed to avoid repeated subtraction - double _requeueThresholdFactor; // alpha * eps; multiplied by degree to get per-node threshold + double _alpha; + double _oneMinusAlpha; // precomputed 1 - alpha + double _requeueThresholdFactor; // alpha * eps; multiplied by degree for per-node threshold - int32_t _batchSize; // Number of seeds in the current batch - int32_t _numNodeTypes; // Total number of node types (homo + hetero) - int32_t _numNodesInQueue{0}; // Running count of nodes across all seeds / types + int32_t _batchSize; + int32_t _numNodeTypes; + int32_t _numNodesInQueue{0}; - // ------------------------------------------------------------------------- // Graph structure (read-only after construction) - // ------------------------------------------------------------------------- std::vector> _nodeTypeToEdgeTypeIds; std::vector _edgeTypeToDstNtypeId; std::vector _degreeTensors; - // ------------------------------------------------------------------------- - // Per-seed, per-node-type PPR state (indexed [seed_idx][ntype_id]) - // ------------------------------------------------------------------------- + // Per-seed, per-node-type PPR state [seed_idx][ntype_id] std::vector>> _pprScores; std::vector>> _residuals; std::vector>> _queue; - std::vector>> _queuedNodes; + std::vector>> _queuedNodes; // snapshot from drainQueue - // ------------------------------------------------------------------------- - // Neighbor cache - // ------------------------------------------------------------------------- std::unordered_map> _neighborCache; - - // ------------------------------------------------------------------------- - // Diagnostics (populated during the algorithm; read after convergence) - // ------------------------------------------------------------------------- - // Total nodes drained (across all seeds and node types) in each drainQueue() - // call. One entry per loop iteration; useful for understanding convergence speed. std::vector _nodesDrainedPerIteration; }; From fb4d5f413c04707b53627d2180e627670c2be0fa Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 20:51:02 +0000 Subject: [PATCH 131/148] Update --- gigl-core/src/gigl_core/py.typed | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 gigl-core/src/gigl_core/py.typed diff --git a/gigl-core/src/gigl_core/py.typed b/gigl-core/src/gigl_core/py.typed new file mode 100644 index 000000000..e69de29bb From a980fa6c6dceab5f396d811d308f0f89139fe5e7 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 21:00:36 +0000 Subject: [PATCH 132/148] Update --- gigl-core/CMakeLists.txt | 6 ++++-- gigl-core/src/gigl_core/__init__.py | 2 +- gigl-core/src/gigl_core/sampling/__init__.pyi | 0 gigl-core/src/gigl_core/{ => sampling}/ppr_forward_push.pyi | 0 4 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 gigl-core/src/gigl_core/sampling/__init__.pyi rename gigl-core/src/gigl_core/{ => sampling}/ppr_forward_push.pyi (100%) diff --git a/gigl-core/CMakeLists.txt b/gigl-core/CMakeLists.txt index 5b0e6d9f2..a08fa8131 100644 --- a/gigl-core/CMakeLists.txt +++ b/gigl-core/CMakeLists.txt @@ -109,8 +109,10 @@ if(_PYTHON_SRCS) # TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. # PyTorch's own build system sets this; we must define it explicitly here. target_compile_definitions("${_name}" PRIVATE "TORCH_EXTENSION_NAME=${_name}") - # Install into gigl_core/ so the .so is importable as gigl_core.. - install(TARGETS "${_name}" DESTINATION gigl_core) + # Mirror the csrc/ subdirectory into gigl_core/ so the install destination is derived + # automatically from the source location (e.g. csrc/sampling/ → gigl_core/sampling/). + file(RELATIVE_PATH _rel_dir "${CMAKE_SOURCE_DIR}/csrc" "${_dir}") + install(TARGETS "${_name}" DESTINATION "gigl_core/${_rel_dir}") endforeach() endif() diff --git a/gigl-core/src/gigl_core/__init__.py b/gigl-core/src/gigl_core/__init__.py index 7bf8c9987..af37d95b9 100644 --- a/gigl-core/src/gigl_core/__init__.py +++ b/gigl-core/src/gigl_core/__init__.py @@ -1,5 +1,5 @@ try: - from gigl_core.ppr_forward_push import PPRForwardPushState + from gigl_core.sampling.ppr_forward_push import PPRForwardPushState except ImportError as e: raise ImportError( f"Failed to import PPR C++ extension: {e}. " diff --git a/gigl-core/src/gigl_core/sampling/__init__.pyi b/gigl-core/src/gigl_core/sampling/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/gigl-core/src/gigl_core/ppr_forward_push.pyi b/gigl-core/src/gigl_core/sampling/ppr_forward_push.pyi similarity index 100% rename from gigl-core/src/gigl_core/ppr_forward_push.pyi rename to gigl-core/src/gigl_core/sampling/ppr_forward_push.pyi From 8b433dc6fbf6048869cad593fa5b896f8020cd76 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 21:06:59 +0000 Subject: [PATCH 133/148] Restore to flat --- gigl-core/CMakeLists.txt | 6 ++---- gigl-core/src/gigl_core/__init__.py | 2 +- gigl-core/src/gigl_core/{sampling => }/ppr_forward_push.pyi | 0 gigl-core/src/gigl_core/sampling/__init__.pyi | 0 4 files changed, 3 insertions(+), 5 deletions(-) rename gigl-core/src/gigl_core/{sampling => }/ppr_forward_push.pyi (100%) delete mode 100644 gigl-core/src/gigl_core/sampling/__init__.pyi diff --git a/gigl-core/CMakeLists.txt b/gigl-core/CMakeLists.txt index a08fa8131..5b0e6d9f2 100644 --- a/gigl-core/CMakeLists.txt +++ b/gigl-core/CMakeLists.txt @@ -109,10 +109,8 @@ if(_PYTHON_SRCS) # TORCH_EXTENSION_NAME is used in PYBIND11_MODULE() to name the module. # PyTorch's own build system sets this; we must define it explicitly here. target_compile_definitions("${_name}" PRIVATE "TORCH_EXTENSION_NAME=${_name}") - # Mirror the csrc/ subdirectory into gigl_core/ so the install destination is derived - # automatically from the source location (e.g. csrc/sampling/ → gigl_core/sampling/). - file(RELATIVE_PATH _rel_dir "${CMAKE_SOURCE_DIR}/csrc" "${_dir}") - install(TARGETS "${_name}" DESTINATION "gigl_core/${_rel_dir}") + # Install into gigl_core/ so the .so is importable as gigl_core.. + install(TARGETS "${_name}" DESTINATION gigl_core) endforeach() endif() diff --git a/gigl-core/src/gigl_core/__init__.py b/gigl-core/src/gigl_core/__init__.py index af37d95b9..7bf8c9987 100644 --- a/gigl-core/src/gigl_core/__init__.py +++ b/gigl-core/src/gigl_core/__init__.py @@ -1,5 +1,5 @@ try: - from gigl_core.sampling.ppr_forward_push import PPRForwardPushState + from gigl_core.ppr_forward_push import PPRForwardPushState except ImportError as e: raise ImportError( f"Failed to import PPR C++ extension: {e}. " diff --git a/gigl-core/src/gigl_core/sampling/ppr_forward_push.pyi b/gigl-core/src/gigl_core/ppr_forward_push.pyi similarity index 100% rename from gigl-core/src/gigl_core/sampling/ppr_forward_push.pyi rename to gigl-core/src/gigl_core/ppr_forward_push.pyi diff --git a/gigl-core/src/gigl_core/sampling/__init__.pyi b/gigl-core/src/gigl_core/sampling/__init__.pyi deleted file mode 100644 index e69de29bb..000000000 From 0ed553a02a3585eee82cc2529474257d25ce7f8b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 21:08:41 +0000 Subject: [PATCH 134/148] Update --- gigl-core/src/gigl_core/__init__.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/gigl-core/src/gigl_core/__init__.py b/gigl-core/src/gigl_core/__init__.py index 7bf8c9987..7c23be783 100644 --- a/gigl-core/src/gigl_core/__init__.py +++ b/gigl-core/src/gigl_core/__init__.py @@ -1,11 +1,3 @@ -try: - from gigl_core.ppr_forward_push import PPRForwardPushState -except ImportError as e: - raise ImportError( - f"Failed to import PPR C++ extension: {e}. " - "If the extension is not yet compiled, run `uv pip install -e gigl-core/` from the GiGL root. " - "If it is compiled, ensure `import torch` is called before importing this module " - "so that libtorch shared libraries are loaded into the process first." - ) from e +from gigl_core.ppr_forward_push import PPRForwardPushState __all__ = ["PPRForwardPushState"] From 6c6c47757baa9a8e6ac8b7bc27364388c3ba0ba2 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 21:29:30 +0000 Subject: [PATCH 135/148] Update --- gigl-core/csrc/sampling/ppr_forward_push.cpp | 13 +++---- gigl-core/tests/ppr_forward_push_test.cpp | 40 +++++++++++--------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/gigl-core/csrc/sampling/ppr_forward_push.cpp b/gigl-core/csrc/sampling/ppr_forward_push.cpp index daf4f1c2b..6e1728271 100644 --- a/gigl-core/csrc/sampling/ppr_forward_push.cpp +++ b/gigl-core/csrc/sampling/ppr_forward_push.cpp @@ -274,14 +274,11 @@ int32_t PPRForwardPushState::getTotalDegree(int32_t nodeId, int32_t ntypeId) con if (t.numel() == 0) { return 0; } - TORCH_CHECK(nodeId >= 0 && nodeId < static_cast(t.size(0)), - "Node ID ", - nodeId, - " out of range for degree tensor of ntype_id ", - ntypeId, - " (size=", - t.size(0), - "). This indicates corrupted graph data or a sampler bug."); + TORCH_CHECK(nodeId >= 0, + "Node ID ", nodeId, " is negative, which indicates a sampler bug."); + TORCH_CHECK(nodeId < static_cast(t.size(0)), + "Node ID ", nodeId, " out of range for degree tensor of ntype_id ", + ntypeId, " (size=", t.size(0), "). This indicates corrupted graph data or a sampler bug."); // data_ptr() returns a raw C pointer to the tensor's int32 data buffer. return t.data_ptr()[nodeId]; } diff --git a/gigl-core/tests/ppr_forward_push_test.cpp b/gigl-core/tests/ppr_forward_push_test.cpp index 2203e3032..cbecaa38f 100644 --- a/gigl-core/tests/ppr_forward_push_test.cpp +++ b/gigl-core/tests/ppr_forward_push_test.cpp @@ -17,9 +17,22 @@ static PPRForwardPushState makeState( {torch::tensor(degrees, torch::kInt)}); } +// Convenience wrapper: build the fetchedByEtypeId argument for pushResiduals +// from flat vectors, keeping test call sites readable. +static std::unordered_map> +makeFetched(int32_t etypeId, + std::vector nodeIds, + std::vector flatNbrs, + std::vector counts) { + return {{etypeId, + {torch::tensor(nodeIds, torch::kLong), + torch::tensor(flatNbrs, torch::kLong), + torch::tensor(counts, torch::kLong)}}}; +} + // After construction, drainQueue() returns the seed node under etype 0. TEST(PPRForwardPush, DrainQueueReturnsSeedNodeInitially) { - auto state = makeState({0}, 0.15, 1e-6, {1}); + auto state = makeState(/*seeds=*/{0}, /*alpha=*/0.15, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{1}); auto result = state.drainQueue(); ASSERT_TRUE(result.has_value()); ASSERT_NE(result->find(0), result->end()); @@ -29,7 +42,7 @@ TEST(PPRForwardPush, DrainQueueReturnsSeedNodeInitially) { // After convergence (sink node absorbs all residual), drainQueue() returns nullopt. TEST(PPRForwardPush, DrainQueueReturnsNulloptAfterConvergence) { - auto state = makeState({0}, 0.15, 1e-6, {0}); // node 0 is a sink (degree 0) + auto state = makeState(/*seeds=*/{0}, /*alpha=*/0.15, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{0}); state.drainQueue(); state.pushResiduals({}); EXPECT_FALSE(state.drainQueue().has_value()); @@ -38,7 +51,7 @@ TEST(PPRForwardPush, DrainQueueReturnsNulloptAfterConvergence) { // A sink seed node absorbs its full residual as PPR score (= alpha). TEST(PPRForwardPush, PprScoreAbsorbsAlpha) { const double alpha = 0.15; - auto state = makeState({0}, alpha, 1e-6, {0}); + auto state = makeState(/*seeds=*/{0}, alpha, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{0}); state.drainQueue(); state.pushResiduals({}); auto topk = state.extractTopK(10); @@ -51,14 +64,11 @@ TEST(PPRForwardPush, PprScoreAbsorbsAlpha) { // Node 0 (degree 1) pushes (1-alpha)*alpha residual to node 1 (sink). TEST(PPRForwardPush, ResidualDistributedToNeighbor) { const double alpha = 0.15; - auto state = makeState({0}, alpha, 1e-6, {1, 0}); + auto state = makeState(/*seeds=*/{0}, alpha, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{1, 0}); // Iteration 1: seed node 0 → neighbor node 1. state.drainQueue(); - state.pushResiduals({{0, - {torch::tensor(std::vector{0}, torch::kLong), - torch::tensor(std::vector{1}, torch::kLong), - torch::tensor(std::vector{1}, torch::kLong)}}}); + state.pushResiduals(makeFetched(/*etypeId=*/0, /*nodeIds=*/{0}, /*flatNbrs=*/{1}, /*counts=*/{1})); // Iteration 2: node 1 is a sink; absorbs its residual, no further push. state.drainQueue(); @@ -79,13 +89,10 @@ TEST(PPRForwardPush, ResidualDistributedToNeighbor) { // Two seeds both push residual to node 2; the neighbor-lookup request deduplicates // to one entry, but getNodesDrainedPerIteration counts both seed queues. TEST(PPRForwardPush, DeduplicatesNodesAcrossSeeds) { - auto state = makeState({0, 1}, 0.15, 1e-6, {1, 1, 0}); + auto state = makeState(/*seeds=*/{0, 1}, /*alpha=*/0.15, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{1, 1, 0}); state.drainQueue(); - state.pushResiduals({{0, - {torch::tensor(std::vector{0, 1}, torch::kLong), - torch::tensor(std::vector{2, 2}, torch::kLong), - torch::tensor(std::vector{1, 1}, torch::kLong)}}}); + state.pushResiduals(makeFetched(/*etypeId=*/0, /*nodeIds=*/{0, 1}, /*flatNbrs=*/{2, 2}, /*counts=*/{1, 1})); auto iter2 = state.drainQueue(); ASSERT_TRUE(iter2.has_value()); @@ -96,13 +103,10 @@ TEST(PPRForwardPush, DeduplicatesNodesAcrossSeeds) { // extractTopK respects the maxPprNodes limit. TEST(PPRForwardPush, ExtractTopKLimitsResults) { - auto state = makeState({0}, 0.15, 1e-6, {1, 0}); + auto state = makeState(/*seeds=*/{0}, /*alpha=*/0.15, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{1, 0}); state.drainQueue(); - state.pushResiduals({{0, - {torch::tensor(std::vector{0}, torch::kLong), - torch::tensor(std::vector{1}, torch::kLong), - torch::tensor(std::vector{1}, torch::kLong)}}}); + state.pushResiduals(makeFetched(/*etypeId=*/0, /*nodeIds=*/{0}, /*flatNbrs=*/{1}, /*counts=*/{1})); state.drainQueue(); state.pushResiduals({}); From 70100a6cc8a21f220a587e3aef0545c67794fabb Mon Sep 17 00:00:00 2001 From: mkolodner Date: Wed, 29 Apr 2026 22:42:34 +0000 Subject: [PATCH 136/148] Update --- gigl-core/csrc/sampling/ppr_forward_push.cpp | 10 ++++++++-- gigl-core/csrc/sampling/ppr_forward_push.h | 8 -------- gigl/distributed/utils/neighborloader.py | 7 ++++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/gigl-core/csrc/sampling/ppr_forward_push.cpp b/gigl-core/csrc/sampling/ppr_forward_push.cpp index 6e1728271..87d5699d4 100644 --- a/gigl-core/csrc/sampling/ppr_forward_push.cpp +++ b/gigl-core/csrc/sampling/ppr_forward_push.cpp @@ -1,5 +1,12 @@ #include "ppr_forward_push.h" +// Pack (node_id, etype_id) into a single uint64 for use as a hash key. +// Inputs are cast through uint32_t to avoid sign-extension of negative int32 values. +static inline uint64_t packKey(int32_t nodeId, int32_t etypeId) { + return (static_cast(static_cast(nodeId)) << 32) | + static_cast(etypeId); +} + PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, int32_t seedNodeTypeId, double alpha, @@ -8,7 +15,6 @@ PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, std::vector edgeTypeToDstNtypeId, std::vector degreeTensors) : _alpha(alpha), - _oneMinusAlpha(1.0 - alpha), _requeueThresholdFactor(requeueThresholdFactor), // std::move transfers ownership of each vector into the member variable // without copying its contents — equivalent to Python's list hand-off @@ -169,7 +175,7 @@ void PPRForwardPushState::pushResiduals( continue; } - double resPerNbr = _oneMinusAlpha * res / static_cast(totalFetched); + double resPerNbr = (1.0 - _alpha) * res / static_cast(totalFetched); for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { // Invariant: fetched and _neighborCache are mutually exclusive for diff --git a/gigl-core/csrc/sampling/ppr_forward_push.h b/gigl-core/csrc/sampling/ppr_forward_push.h index ac7366ee5..3a005e5a3 100644 --- a/gigl-core/csrc/sampling/ppr_forward_push.h +++ b/gigl-core/csrc/sampling/ppr_forward_push.h @@ -10,13 +10,6 @@ #include #include -// Pack (node_id, etype_id) into a single uint64 for use as a hash key. -// Inputs are cast through uint32_t to avoid sign-extension of negative int32 values. -static inline uint64_t packKey(int32_t nodeId, int32_t etypeId) { - return (static_cast(static_cast(nodeId)) << 32) | - static_cast(etypeId); -} - // C++ kernel for PPR Forward Push (Andersen et al., 2006). // Hot-loop state lives here; distributed neighbor fetches are driven from Python. // @@ -61,7 +54,6 @@ class PPRForwardPushState { [[nodiscard]] int32_t getTotalDegree(int32_t nodeId, int32_t ntypeId) const; double _alpha; - double _oneMinusAlpha; // precomputed 1 - alpha double _requeueThresholdFactor; // alpha * eps; multiplied by degree for per-node threshold int32_t _batchSize; diff --git a/gigl/distributed/utils/neighborloader.py b/gigl/distributed/utils/neighborloader.py index 8ea4c86f4..bac714738 100644 --- a/gigl/distributed/utils/neighborloader.py +++ b/gigl/distributed/utils/neighborloader.py @@ -190,9 +190,10 @@ def strip_non_ppr_edge_types( for edge_type in list(data.edge_types): if edge_type not in ppr_edge_types: del data[edge_type] - # GLT does not guarantee an entry in num_sampled_edges for every edge type - # (e.g. types with zero samples may be absent), so use pop instead of del. - data.num_sampled_edges.pop(edge_type, None) + # num_sampled_edges may not exist at all (e.g. in tests or when GLT doesn't + # populate it), and may lack entries for edge types with zero samples. + if hasattr(data, "num_sampled_edges"): + data.num_sampled_edges.pop(edge_type, None) return data From fe26f5a67e7719793b0026830fd44308803cd29b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 30 Apr 2026 21:43:59 +0000 Subject: [PATCH 137/148] Update --- .clang-tidy | 4 +- Makefile | 2 +- docs/cpp_style_guide.md | 10 +- gigl-core/CMakeLists.txt | 8 +- gigl-core/Makefile | 4 +- .../sampling/ppr_forward_push.cpp | 147 ++++++++++++------ .../sampling/ppr_forward_push.h | 45 +++++- .../sampling/python_ppr_forward_push.cpp | 49 ++---- gigl-core/pyproject.toml | 8 +- gigl-core/src/gigl_core/py.typed | 1 + gigl-core/tests/CMakeLists.txt | 8 +- gigl-core/tests/ppr_forward_push_test.cpp | 2 + gigl/distributed/base_sampler.py | 43 +++++ gigl/distributed/dist_neighbor_sampler.py | 9 ++ gigl/distributed/dist_ppr_sampler.py | 31 ++-- .../distributed/distributed_neighborloader.py | 6 + gigl/distributed/sampler.py | 4 + gigl/distributed/utils/dist_sampler.py | 1 + gigl/distributed/utils/neighborloader.py | 5 +- 19 files changed, 256 insertions(+), 131 deletions(-) rename gigl-core/{csrc => core}/sampling/ppr_forward_push.cpp (65%) rename gigl-core/{csrc => core}/sampling/ppr_forward_push.h (54%) rename gigl-core/{csrc => core}/sampling/python_ppr_forward_push.cpp (52%) diff --git a/.clang-tidy b/.clang-tidy index 5dd99dd83..d5702893d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -47,10 +47,10 @@ Checks: > # Warnings from headers outside the regex (PyTorch, pybind11, etc.) are suppressed # entirely and never reach WarningsAsErrors — so the large warning counts printed # by clang-tidy ("N warnings generated") are third-party noise that is silently -# dropped. Only diagnostics in our own headers (.*/gigl/csrc/.*) are reported, +# dropped. Only diagnostics in our own headers (.*/gigl-core/core/.*) are reported, # and those are treated as hard errors. WarningsAsErrors: '*' -HeaderFilterRegex: '.*/gigl-core/csrc/.*' +HeaderFilterRegex: '.*/gigl-core/core/.*' FormatStyle: none # CheckOptions: per-check tuning parameters. Each entry configures a specific # option for an individual check, using the form: diff --git a/Makefile b/Makefile index 9db02bb80..9dc8212d9 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ DOCKER_IMAGE_MAIN_CPU_NAME_WITH_TAG?=${DOCKER_IMAGE_MAIN_CPU_NAME}:${DATE} DOCKER_IMAGE_DEV_WORKBENCH_NAME_WITH_TAG?=${DOCKER_IMAGE_DEV_WORKBENCH_NAME}:${DATE} PYTHON_DIRS:=.github/scripts examples gigl tests snapchat scripts -CPP_SOURCES:=$(shell find gigl-core/csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) +CPP_SOURCES:=$(shell find gigl-core/core \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) # clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). # Exclude .cu files from tidy targets; clang-format and clangd handle them fine. CPP_SOURCES_NO_CUDA:=$(filter-out %.cu,$(CPP_SOURCES)) diff --git a/docs/cpp_style_guide.md b/docs/cpp_style_guide.md index 0a9e684ab..cb38358d0 100644 --- a/docs/cpp_style_guide.md +++ b/docs/cpp_style_guide.md @@ -163,7 +163,7 @@ Enforced via `readability-identifier-naming`: | Option | Value | Effect | | ---------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `WarningsAsErrors` | `*` | Every check failure is a hard error in CI | -| `HeaderFilterRegex` | `.*/gigl-core/csrc/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | +| `HeaderFilterRegex` | `.*/gigl-core/core/.*` | Scopes checks to our own headers. Using `.*` causes clang-tidy to report warnings from every PyTorch/pybind11 header it parses, flooding output with thousands of third-party issues. | | `FormatStyle` | `none` | clang-tidy does not auto-reformat; use clang-format separately | | `bugprone-string-constructor.LargeLengthThreshold` | `8388608` (8 MB) | Strings larger than 8 MB from a length argument are flagged | | `modernize-loop-convert.NamingStyle` | `camelBack` | Auto-generated loop variable names use camelBack, matching `readability-identifier-naming.VariableCase` | @@ -174,7 +174,7 @@ ______________________________________________________________________ ## pybind11 Extension Modules -Extension modules live under `gigl-core/csrc/`. +Extension modules live under `gigl-core/core/`. ### Naming convention @@ -184,11 +184,11 @@ Extension modules live under `gigl-core/csrc/`. | `.cpp` / `.cu` | Implementation — function and class definitions | | `.h` | Declarations (function signatures, class definitions, constants) | -Example: to add a `my_op` extension under `gigl-core/csrc/sampling/`: +Example: to add a `my_op` extension under `gigl-core/core/sampling/`: ``` -gigl-core/csrc/sampling/python_my_op.cpp ← pybind11 bindings -gigl-core/csrc/sampling/my_op.cpp ← implementation +gigl-core/core/sampling/python_my_op.cpp ← pybind11 bindings +gigl-core/core/sampling/my_op.cpp ← implementation ``` The compiled `.so` is installed into the `gigl_core` package and importable as `gigl_core.`. diff --git a/gigl-core/CMakeLists.txt b/gigl-core/CMakeLists.txt index 5b0e6d9f2..3e39eb669 100644 --- a/gigl-core/CMakeLists.txt +++ b/gigl-core/CMakeLists.txt @@ -26,19 +26,19 @@ endif() # --------------------------------------------------------------------------- # Extension modules — auto-discovered. -# Files named python_*.cpp under csrc/ are compiled as pybind11 extension +# Files named python_*.cpp under core/ are compiled as pybind11 extension # modules. The companion .cpp (without the "python_" prefix) is included # automatically when present. Add a new extension by dropping source files # here; no changes to this CMakeLists.txt are needed. # --------------------------------------------------------------------------- if(CMAKE_CUDA_COMPILER) file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/csrc/python_*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/csrc/python_*.cu" + "${CMAKE_CURRENT_SOURCE_DIR}/core/python_*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/core/python_*.cu" ) else() file(GLOB_RECURSE _PYTHON_SRCS CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/csrc/python_*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/core/python_*.cpp" ) endif() diff --git a/gigl-core/Makefile b/gigl-core/Makefile index f3f63c7b8..572799dff 100644 --- a/gigl-core/Makefile +++ b/gigl-core/Makefile @@ -2,7 +2,7 @@ # Invoked from the GiGL repo root via: $(MAKE) -C gigl-core # All paths below are relative to gigl-core/. -CPP_SOURCES := $(shell find csrc \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) +CPP_SOURCES := $(shell find core \( -name "*.cpp" -o -name "*.cu" \) 2>/dev/null) # clang-tidy 15 does not fully support CUDA syntax (e.g. <<<...>>>, __global__). # Exclude .cu files from tidy targets; clang-format and clangd handle them fine. CPP_SOURCES_NO_CUDA := $(filter-out %.cu,$(CPP_SOURCES)) @@ -12,7 +12,7 @@ CPP_SOURCES_NO_CUDA := $(filter-out %.cu,$(CPP_SOURCES)) # pyproject.toml, make skips the reinstall unless something actually changed. # We cd to the repo root so that no-build-isolation-package in the root pyproject.toml # is respected by uv pip install. -.cache/cmake_build/CMakeInit.txt: $(shell find csrc \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) CMakeLists.txt pyproject.toml +.cache/cmake_build/CMakeInit.txt: $(shell find core \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) CMakeLists.txt pyproject.toml cd $(abspath $(CURDIR)/..) && uv pip install -e gigl-core/ build_cpp_extensions: .cache/cmake_build/CMakeInit.txt diff --git a/gigl-core/csrc/sampling/ppr_forward_push.cpp b/gigl-core/core/sampling/ppr_forward_push.cpp similarity index 65% rename from gigl-core/csrc/sampling/ppr_forward_push.cpp rename to gigl-core/core/sampling/ppr_forward_push.cpp index 87d5699d4..06545f58e 100644 --- a/gigl-core/csrc/sampling/ppr_forward_push.cpp +++ b/gigl-core/core/sampling/ppr_forward_push.cpp @@ -1,8 +1,20 @@ #include "ppr_forward_push.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace gigl { + // Pack (node_id, etype_id) into a single uint64 for use as a hash key. // Inputs are cast through uint32_t to avoid sign-extension of negative int32 values. -static inline uint64_t packKey(int32_t nodeId, int32_t etypeId) { +static uint64_t packKey(int32_t nodeId, int32_t etypeId) { return (static_cast(static_cast(nodeId)) << 32) | static_cast(etypeId); } @@ -23,9 +35,33 @@ PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, _edgeTypeToDstNtypeId(std::move(edgeTypeToDstNtypeId)), _degreeTensors(std::move(degreeTensors)) { TORCH_CHECK(seedNodes.dim() == 1, "seedNodes must be 1D"); + // int32_t is sufficient: batch sizes approaching 2B seeds are not a realistic concern. _batchSize = static_cast(seedNodes.size(0)); _numNodeTypes = static_cast(_nodeTypeToEdgeTypeIds.size()); + TORCH_CHECK(seedNodeTypeId >= 0, + "seedNodeTypeId ", seedNodeTypeId, " is negative."); + TORCH_CHECK(seedNodeTypeId < _numNodeTypes, + "seedNodeTypeId ", seedNodeTypeId, " out of range [0, ", _numNodeTypes, ")."); + auto numEdgeTypes = static_cast(_edgeTypeToDstNtypeId.size()); + for (int32_t eid = 0; eid < numEdgeTypes; ++eid) { + int32_t dstNt = _edgeTypeToDstNtypeId[eid]; + TORCH_CHECK(dstNt >= 0, + "edgeTypeToDstNtypeId[", eid, "] = ", dstNt, " is negative."); + TORCH_CHECK(dstNt < _numNodeTypes, + "edgeTypeToDstNtypeId[", eid, "] = ", dstNt, + " out of range [0, ", _numNodeTypes, ")."); + } + for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { + for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { + TORCH_CHECK(eid >= 0, + "nodeTypeToEdgeTypeIds[", nt, "] contains negative edge type id ", eid, "."); + TORCH_CHECK(eid < numEdgeTypes, + "nodeTypeToEdgeTypeIds[", nt, "] contains edge type id ", eid, + " out of range [0, ", numEdgeTypes, ")."); + } + } + // Allocate per-seed, per-node-type tables. // .assign(n, val) fills a vector with n copies of val — like [val] * n in Python. _pprScores.assign(_batchSize, std::vector>(_numNodeTypes)); @@ -53,6 +89,8 @@ std::optional> PPRForwardPushState::d } // Reset the snapshot from the previous iteration. + // TODO: if this loop becomes a bottleneck, consider parallelising with + // std::for_each(std::execution::par_unseq, ...) or adding vectorisation hints. for (int32_t s = 0; s < _batchSize; ++s) { for (auto& qs : _queuedNodes[s]) { qs.clear(); @@ -71,11 +109,14 @@ std::optional> PPRForwardPushState::d continue; } - // Move the live queue into the snapshot (no data copy — O(1)). + // Move the live queue into the snapshot in O(1) — avoids copying all node IDs. + // The explicit clear() after move is defensive: the standard only guarantees + // a moved-from container is "valid but unspecified", not necessarily empty. _queuedNodes[s][nt] = std::move(_queue[s][nt]); _queue[s][nt].clear(); - totalDrainedThisRound += static_cast(_queuedNodes[s][nt].size()); - _numNodesInQueue -= static_cast(_queuedNodes[s][nt].size()); + auto numDrained = static_cast(_queuedNodes[s][nt].size()); + totalDrainedThisRound += numDrained; + _numNodesInQueue -= numDrained; for (int32_t nodeId : _queuedNodes[s][nt]) { for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { @@ -90,7 +131,7 @@ std::optional> PPRForwardPushState::d _nodesDrainedPerIteration.push_back(totalDrainedThisRound); std::unordered_map result; - for (auto& [eid, nodeSet] : nodesToLookup) { + for (const auto& [eid, nodeSet] : nodesToLookup) { std::vector ids(nodeSet.begin(), nodeSet.end()); result[eid] = torch::tensor(ids, torch::kLong); } @@ -159,18 +200,23 @@ void PPRForwardPushState::pushResiduals( // ones (which matters when num_neighbors_per_hop < true_degree). int32_t totalFetched = 0; for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { - auto fi = fetched.find(packKey(src, eid)); - if (fi != fetched.end()) { - totalFetched += static_cast(fi->second.size()); + auto fetchedEntry = fetched.find(packKey(src, eid)); + if (fetchedEntry != fetched.end()) { + totalFetched += static_cast(fetchedEntry->second.size()); } else { - auto ci = _neighborCache.find(packKey(src, eid)); - if (ci != _neighborCache.end()) { - totalFetched += static_cast(ci->second.size()); + auto cachedEntry = _neighborCache.find(packKey(src, eid)); + if (cachedEntry != _neighborCache.end()) { + totalFetched += static_cast(cachedEntry->second.size()); } } } - // Destination-only nodes (or nodes with no fetched neighbors) absorb - // residual but do not push further. + // Two cases reach here: + // 1. True sink node (no outgoing edges): absorbing the full residual is correct. + // 2. Budget exhausted, no cache entry: the (1-α)·r that should flow to + // neighbors has nowhere to go, so it gets absorbed into src's score instead. + // This overstates src and understates its neighbors. This is expected + // behavior when max_fetch_iterations is set, which intentionally trades + // theoretical PPR correctness for better throughput. if (totalFetched == 0) { continue; } @@ -182,14 +228,18 @@ void PPRForwardPushState::pushResiduals( // any given (node, etype) key within one iteration. drainQueue() // only requests a fetch for nodes absent from _neighborCache, so a // key is in at most one of the two. + // Points at the neighbor list we will distribute residual to — + // either from `fetched` (new this iteration) or `_neighborCache` + // (seen in a previous iteration). Null if neither has data for + // this (node, etype) pair. Does not own any memory. const std::vector* nbrList = nullptr; - auto fi = fetched.find(packKey(src, eid)); - if (fi != fetched.end()) { - nbrList = &fi->second; + auto fetchedEntry = fetched.find(packKey(src, eid)); + if (fetchedEntry != fetched.end()) { + nbrList = &fetchedEntry->second; } else { - auto ci = _neighborCache.find(packKey(src, eid)); - if (ci != _neighborCache.end()) { - nbrList = &ci->second; + auto cachedEntry = _neighborCache.find(packKey(src, eid)); + if (cachedEntry != _neighborCache.end()) { + nbrList = &cachedEntry->second; } } if (!nbrList || nbrList->empty()) { @@ -215,9 +265,9 @@ void PPRForwardPushState::pushResiduals( for (int32_t peid : _nodeTypeToEdgeTypeIds[dstNt]) { uint64_t pk = packKey(nbr, peid); if (_neighborCache.find(pk) == _neighborCache.end()) { - auto pfi = fetched.find(pk); - if (pfi != fetched.end()) { - _neighborCache[pk] = pfi->second; + auto fetchedNbrEntry = fetched.find(pk); + if (fetchedNbrEntry != fetched.end()) { + _neighborCache[pk] = fetchedNbrEntry->second; } } } @@ -231,38 +281,31 @@ void PPRForwardPushState::pushResiduals( std::unordered_map> PPRForwardPushState::extractTopK( int32_t maxPprNodes) { - std::unordered_set active; - for (int32_t s = 0; s < _batchSize; ++s) { - for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { - if (!_pprScores[s][nt].empty()) { - active.insert(nt); - } - } - } - std::unordered_map> result; - for (int32_t nt : active) { + // Emit an entry for every node type, even if unreachable in this batch (empty tensors, + // all-zero valid_counts). This keeps the output shape consistent across batches so + // downstream model architectures see a fixed set of PPR edge types every iteration. + for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { std::vector flatIds; std::vector flatWeights; std::vector validCounts; - for (int32_t s = 0; s < _batchSize; ++s) { - const auto& scores = _pprScores[s][nt]; - int32_t k = std::min(maxPprNodes, static_cast(scores.size())); - if (k > 0) { - std::vector> items(scores.begin(), scores.end()); - std::partial_sort(items.begin(), items.begin() + k, items.end(), [](const auto& a, const auto& b) { - return a.second > b.second; - }); - - for (int32_t i = 0; i < k; ++i) { - flatIds.push_back(static_cast(items[i].first)); + for (int32_t seedIdx = 0; seedIdx < _batchSize; ++seedIdx) { + const auto& scores = _pprScores[seedIdx][nt]; + int32_t topK = std::min(maxPprNodes, static_cast(scores.size())); + if (topK > 0) { + std::vector> scorePairs(scores.begin(), scores.end()); + std::partial_sort(scorePairs.begin(), scorePairs.begin() + topK, scorePairs.end(), + [](const auto& a, const auto& b) { return a.second > b.second; }); + + for (int32_t i = 0; i < topK; ++i) { + flatIds.push_back(static_cast(scorePairs[i].first)); // Cast to float32 for output; internal scores stay double to // avoid accumulated rounding errors in the push loop. - flatWeights.push_back(static_cast(items[i].second)); + flatWeights.push_back(static_cast(scorePairs[i].second)); } } - validCounts.push_back(static_cast(k)); + validCounts.push_back(static_cast(topK)); } result[nt] = {torch::tensor(flatIds, torch::kLong), @@ -285,6 +328,16 @@ int32_t PPRForwardPushState::getTotalDegree(int32_t nodeId, int32_t ntypeId) con TORCH_CHECK(nodeId < static_cast(t.size(0)), "Node ID ", nodeId, " out of range for degree tensor of ntype_id ", ntypeId, " (size=", t.size(0), "). This indicates corrupted graph data or a sampler bug."); - // data_ptr() returns a raw C pointer to the tensor's int32 data buffer. - return t.data_ptr()[nodeId]; + if (t.scalar_type() == torch::kInt) { + return t.data_ptr()[nodeId]; + } + if (t.scalar_type() == torch::kLong) { + return static_cast( + std::min(t.data_ptr()[nodeId], INT32_MAX)); + } + TORCH_CHECK(false, "Unsupported degree tensor dtype: ", t.scalar_type(), + ". Expected torch.int32 or torch.int64."); + return 0; // unreachable; suppresses compiler warning } + +} // namespace gigl diff --git a/gigl-core/csrc/sampling/ppr_forward_push.h b/gigl-core/core/sampling/ppr_forward_push.h similarity index 54% rename from gigl-core/csrc/sampling/ppr_forward_push.h rename to gigl-core/core/sampling/ppr_forward_push.h index 3a005e5a3..003afca3b 100644 --- a/gigl-core/csrc/sampling/ppr_forward_push.h +++ b/gigl-core/core/sampling/ppr_forward_push.h @@ -10,6 +10,8 @@ #include #include +namespace gigl { + // C++ kernel for PPR Forward Push (Andersen et al., 2006). // Hot-loop state lives here; distributed neighbor fetches are driven from Python. // @@ -42,7 +44,8 @@ class PPRForwardPushState { fetchedByEtypeId); // Return top-k PPR nodes per seed per node type. - // Result: {ntype_id: (flat_ids, flat_weights, valid_counts)} — one entry per active ntype. + // Result: {ntype_id: (flat_ids, flat_weights, valid_counts)} — one entry per node type, + // including types unreachable in this batch (empty tensors, all-zero valid_counts). std::unordered_map> extractTopK(int32_t maxPprNodes); @@ -54,23 +57,49 @@ class PPRForwardPushState { [[nodiscard]] int32_t getTotalDegree(int32_t nodeId, int32_t ntypeId) const; double _alpha; - double _requeueThresholdFactor; // alpha * eps; multiplied by degree for per-node threshold + double _requeueThresholdFactor; // alpha * eps; per-node requeue threshold = factor * degree - int32_t _batchSize; - int32_t _numNodeTypes; - int32_t _numNodesInQueue{0}; + int32_t _batchSize; // number of seed nodes in the current batch + int32_t _numNodeTypes; // total distinct node types (1 for homogeneous graphs) + int32_t _numNodesInQueue{0}; // running count of queued nodes across all seeds and types - // Graph structure (read-only after construction) + // Graph structure — set at construction, read-only during the algorithm. + // _nodeTypeToEdgeTypeIds[ntype_id] → list of edge type IDs that originate from that node type. + // _edgeTypeToDstNtypeId[etype_id] → destination node type ID for that edge type. + // _degreeTensors[ntype_id] → int32 tensor of total out-degrees, indexed by node ID. std::vector> _nodeTypeToEdgeTypeIds; std::vector _edgeTypeToDstNtypeId; std::vector _degreeTensors; - // Per-seed, per-node-type PPR state [seed_idx][ntype_id] + // Per-seed, per-node-type PPR state. All four tables share the same nesting: + // + // outer vector [_batchSize] — one entry per seed node in the batch + // inner vector [_numNodeTypes] — one entry per node type in the graph + // map / set {node_id → …} — only nodes reached during the walk are present + // + // int32_t is used for node and type IDs throughout to match PyG/GLT's signed-integer + // convention (torch.int32 / torch.int64). Signed types also make nodeId >= 0 checks + // meaningful — an unsigned type would make that guard tautological. + // + // All four tables are sized [_batchSize][_numNodeTypes] at construction and never + // resized, so [seedIdx][nt] indexing is always safe within the loop bounds. + // + // _pprScores: absorbed PPR mass — the final output scores written by pushResiduals(). + // _residuals: unabsorbed mass waiting to be pushed to neighbors. + // _queue: nodes whose residual exceeds the requeue threshold; drained each iteration. + // _queuedNodes: snapshot of _queue captured by drainQueue() so pushResiduals() knows + // which nodes to process in the current iteration. std::vector>> _pprScores; std::vector>> _residuals; std::vector>> _queue; - std::vector>> _queuedNodes; // snapshot from drainQueue + std::vector>> _queuedNodes; + // Neighbor lists fetched from the distributed graph store, keyed by packKey(node_id, etype_id). + // Populated incrementally as nodes are processed; avoids re-fetching the same node twice. std::unordered_map> _neighborCache; + + // Total nodes drained (across all seeds and types) per drainQueue() call. std::vector _nodesDrainedPerIteration; }; + +} // namespace gigl diff --git a/gigl-core/csrc/sampling/python_ppr_forward_push.cpp b/gigl-core/core/sampling/python_ppr_forward_push.cpp similarity index 52% rename from gigl-core/csrc/sampling/python_ppr_forward_push.cpp rename to gigl-core/core/sampling/python_ppr_forward_push.cpp index 98ff40179..fc1c187a6 100644 --- a/gigl-core/csrc/sampling/python_ppr_forward_push.cpp +++ b/gigl-core/core/sampling/python_ppr_forward_push.cpp @@ -1,33 +1,25 @@ // Python bindings for PPRForwardPushState. // -// Follows PyTorch's csrc convention: pure C++ algorithm lives in -// ppr_forward_push.{h,cpp}; this file only handles type conversion between -// Python (pybind11) and C++ types, then delegates to the C++ implementation. +// Pure C++ algorithm lives in ppr_forward_push.{h,cpp}; this file only handles +// type conversion between Python (pybind11) and C++ types, then delegates to +// the C++ implementation. #include #include +#include +#include +#include + #include "ppr_forward_push.h" namespace py = pybind11; +using gigl::PPRForwardPushState; -// drainQueue: C++ returns std::optional>. -// Exposed to Python as: None (convergence) or dict[int, Tensor]. -static py::object drainQueueWrapper(PPRForwardPushState& self) { - auto result = self.drainQueue(); - if (!result) { - return py::none(); - } - py::dict d; - for (auto& [eid, tensor] : *result) { - d[py::int_(eid)] = tensor; - } - return d; -} - -// pushResiduals: Python passes dict[int, tuple[Tensor, Tensor, Tensor]]. -// Convert to C++ map before delegating. -static void pushResidualsWrapper(PPRForwardPushState& self, const py::dict& fetchedByEtypeId) { +// pushResiduals: a wrapper is needed solely to release the GIL during the C++ push. +// pybind11/stl.h handles all type conversions automatically; the other methods use +// direct member function pointers for the same reason. +static void pushResidualsWrapper(PPRForwardPushState& state, const py::dict& fetchedByEtypeId) { std::unordered_map> cppMap; // Dict iteration touches Python objects — GIL must be held here. for (auto item : fetchedByEtypeId) { @@ -40,19 +32,8 @@ static void pushResidualsWrapper(PPRForwardPushState& self, const py::dict& fetc // from other concurrent PPR coroutines while this push runs. { py::gil_scoped_release release; - self.pushResiduals(cppMap); - } -} - -// extractTopK: C++ returns map>. -// Exposed to Python as dict[int, tuple[Tensor, Tensor, Tensor]]. -static py::dict extractTopKWrapper(PPRForwardPushState& self, int32_t maxPprNodes) { - auto result = self.extractTopK(maxPprNodes); - py::dict d; - for (auto& [nt, tup] : result) { - d[py::int_(nt)] = py::make_tuple(std::get<0>(tup), std::get<1>(tup), std::get<2>(tup)); + state.pushResiduals(cppMap); } - return d; } // TORCH_EXTENSION_NAME is set by PyTorch's build system to match the Python @@ -66,8 +47,8 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { std::vector>, std::vector, std::vector>()) - .def("drain_queue", drainQueueWrapper) + .def("drain_queue", &PPRForwardPushState::drainQueue) .def("push_residuals", pushResidualsWrapper) - .def("extract_top_k", extractTopKWrapper) + .def("extract_top_k", &PPRForwardPushState::extractTopK) .def("get_nodes_drained_per_iteration", &PPRForwardPushState::getNodesDrainedPerIteration); } diff --git a/gigl-core/pyproject.toml b/gigl-core/pyproject.toml index 8fc595572..f7b159954 100644 --- a/gigl-core/pyproject.toml +++ b/gigl-core/pyproject.toml @@ -29,8 +29,8 @@ editable.rebuild = false cache-keys = [ { file = "pyproject.toml" }, { file = "CMakeLists.txt" }, - { file = "csrc/**/*.h" }, - { file = "csrc/**/*.cpp" }, - { file = "csrc/**/*.cu" }, - { file = "csrc/**/*.cuh" }, + { file = "core/**/*.h" }, + { file = "core/**/*.cpp" }, + { file = "core/**/*.cu" }, + { file = "core/**/*.cuh" }, ] diff --git a/gigl-core/src/gigl_core/py.typed b/gigl-core/src/gigl_core/py.typed index e69de29bb..23cb101e4 100644 --- a/gigl-core/src/gigl_core/py.typed +++ b/gigl-core/src/gigl_core/py.typed @@ -0,0 +1 @@ +PEP 561 marker. Presence of this file tells mypy that gigl_core supports type checking. diff --git a/gigl-core/tests/CMakeLists.txt b/gigl-core/tests/CMakeLists.txt index a37aedf7f..dbd669060 100644 --- a/gigl-core/tests/CMakeLists.txt +++ b/gigl-core/tests/CMakeLists.txt @@ -34,17 +34,17 @@ foreach(_prefix IN LISTS CMAKE_PREFIX_PATH) endforeach() find_package(Torch REQUIRED PATHS "${TORCH_CMAKE_PREFIX}") -# Auto-discover all kernel sources under csrc/. python_*.cpp are pybind11 +# Auto-discover all kernel sources under core/. python_*.cpp are pybind11 # extension entry points that belong to the wheel, not to the test library. if(CMAKE_CUDA_COMPILER) - file(GLOB_RECURSE _KERNEL_SRCS "${CMAKE_SOURCE_DIR}/csrc/*.cpp" "${CMAKE_SOURCE_DIR}/csrc/*.cu") + file(GLOB_RECURSE _KERNEL_SRCS "${CMAKE_SOURCE_DIR}/core/*.cpp" "${CMAKE_SOURCE_DIR}/core/*.cu") else() - file(GLOB_RECURSE _KERNEL_SRCS "${CMAKE_SOURCE_DIR}/csrc/*.cpp") + file(GLOB_RECURSE _KERNEL_SRCS "${CMAKE_SOURCE_DIR}/core/*.cpp") endif() list(FILTER _KERNEL_SRCS EXCLUDE REGEX ".*/python_[^/]*$") add_library(gigl_core_kernels STATIC ${_KERNEL_SRCS}) -target_include_directories(gigl_core_kernels PUBLIC "${CMAKE_SOURCE_DIR}/csrc") +target_include_directories(gigl_core_kernels PUBLIC "${CMAKE_SOURCE_DIR}/core") target_link_libraries(gigl_core_kernels PUBLIC "${TORCH_LIBRARIES}") # --------------------------------------------------------------------------- diff --git a/gigl-core/tests/ppr_forward_push_test.cpp b/gigl-core/tests/ppr_forward_push_test.cpp index cbecaa38f..22e461b40 100644 --- a/gigl-core/tests/ppr_forward_push_test.cpp +++ b/gigl-core/tests/ppr_forward_push_test.cpp @@ -1,6 +1,8 @@ #include #include "sampling/ppr_forward_push.h" +using gigl::PPRForwardPushState; + // Builds a single-edge-type, single-node-type PPRForwardPushState. static PPRForwardPushState makeState( std::vector seeds, diff --git a/gigl/distributed/base_sampler.py b/gigl/distributed/base_sampler.py index c0242c997..edb1731eb 100644 --- a/gigl/distributed/base_sampler.py +++ b/gigl/distributed/base_sampler.py @@ -4,6 +4,8 @@ import torch from graphlearn_torch.distributed import DistNeighborSampler as GLTDistNeighborSampler +from graphlearn_torch.distributed.dist_feature import DistFeature +from graphlearn_torch.distributed.event_loop import wrap_torch_future from graphlearn_torch.sampler import ( HeteroSamplerOutput, NodeSamplerInput, @@ -13,6 +15,7 @@ from gigl.distributed.sampler import ( NEGATIVE_LABEL_METADATA_KEY, + NODE_LABELS_METADATA_KEY, POSITIVE_LABEL_METADATA_KEY, ABLPNodeSamplerInput, ) @@ -194,6 +197,46 @@ def _prepare_ablp_inputs( metadata=metadata, ) + async def _attach_full_node_labels_to_metadata( + self, + all_sampled_nodes: torch.Tensor, + metadata: dict[str, torch.Tensor], + ) -> None: + """Fetch all node label columns and stash them in sampler metadata. + + GLT's sampler truncates node labels to a single column (``nlabels.T[0]``) + before assembling the SampleMessage, so ``data.y`` only ever carries the + first label column. This method fetches the full label tensor for all + sampled nodes and stores it in *metadata* under ``NODE_LABELS_METADATA_KEY`` + so that ``DistNeighborLoader._collate_fn`` can replace the truncated + ``data.y`` with the complete multi-column tensor. + + Only has an effect when: + - ``self.dist_node_labels`` is a ``DistFeature`` (i.e., the dataset has + node labels), and + - the fetched label tensor has more than one column (multi-label case). + + For single-label datasets the method is a no-op, and GLT's existing + label path is used unchanged. + + This method supports homogeneous graphs only. Heterogeneous multi-label + support can be added here if needed in the future. + + Args: + all_sampled_nodes: 1-D tensor of global node IDs for all nodes in the + sampled subgraph (``SamplerOutput.node`` for the homogeneous case). + metadata: The metadata dict that will be attached to ``SamplerOutput``. + Modified in-place. + """ + if self.dist_node_labels is None: + return + if not isinstance(self.dist_node_labels, DistFeature): + return + fut = self.dist_node_labels.async_get(all_sampled_nodes) + full_labels: torch.Tensor = await wrap_torch_future(fut) + if full_labels.ndim == 2 and full_labels.shape[1] > 1: + metadata[NODE_LABELS_METADATA_KEY] = full_labels + async def _sample_from_nodes( self, inputs: NodeSamplerInput, diff --git a/gigl/distributed/dist_neighbor_sampler.py b/gigl/distributed/dist_neighbor_sampler.py index a91737b5b..c67744506 100644 --- a/gigl/distributed/dist_neighbor_sampler.py +++ b/gigl/distributed/dist_neighbor_sampler.py @@ -185,4 +185,13 @@ async def _sample_from_nodes( ) self.inducer_pool.put(inducer) + + # For homogeneous graphs with multi-column node labels, stash the full label + # tensor in metadata so _collate_fn can restore it after GLT truncates data.y. + if not is_hetero: + await self._attach_full_node_labels_to_metadata( + all_sampled_nodes=sample_output.node, + metadata=metadata, + ) + return sample_output diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 74ec80a6d..f7f3e41ba 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -13,11 +13,9 @@ from graphlearn_torch.typing import EdgeType, NodeType from graphlearn_torch.utils import merge_dict -from gigl.common.logger import Logger from gigl.distributed.base_sampler import BaseDistNeighborSampler from gigl.types.graph import is_label_edge_type -_logger = Logger() # Trailing "." is an intentional separator. These constants are used both to # write metadata keys (f"{KEY}{repr(edge_type)}" → e.g. "ppr_edge_index.('user', 'to', 'story')") @@ -157,7 +155,7 @@ def __init__( # We include both source types (have outgoing edges) and destination-only # types (no outgoing edges, but may accumulate PPR score during the walk) # so the kernel can index residual/ppr_score tables for any node it sees. - _all_node_types: list[NodeType] = sorted( + all_node_types: list[NodeType] = sorted( {nt for nt in self._node_type_to_edge_types} | { self._get_destination_type(et) @@ -166,20 +164,20 @@ def __init__( } ) # dict.fromkeys preserves insertion order while deduplicating. - _all_edge_types: list[EdgeType] = list( + all_edge_types: list[EdgeType] = list( dict.fromkeys( et for etypes in self._node_type_to_edge_types.values() for et in etypes ) ) self._node_type_to_id: dict[NodeType, int] = { - nt: i for i, nt in enumerate(_all_node_types) + nt: i for i, nt in enumerate(all_node_types) } - self._ntype_id_to_ntype: list[NodeType] = _all_node_types + self._ntype_id_to_ntype: list[NodeType] = all_node_types self._etype_to_etype_id: dict[EdgeType, int] = { - et: i for i, et in enumerate(_all_edge_types) + et: i for i, et in enumerate(all_edge_types) } - self._etype_id_to_etype: list[EdgeType] = _all_edge_types + self._etype_id_to_etype: list[EdgeType] = all_edge_types self._node_type_id_to_edge_type_ids: list[list[int]] = [ [ @@ -295,21 +293,18 @@ async def _batch_fetch_neighbors( # issues a single RPC round-trip; doing them in parallel rather than # sequentially cuts fetch latency from O(num_edge_types) to O(1). eids = list(nodes_by_etype_id.keys()) - outputs: list[NeighborOutput] = await asyncio.gather( - *[ + sample_tasks = [] + for eid in eids: + etype = self._etype_id_to_etype[eid] + sample_tasks.append( self._sample_one_hop( srcs=nodes_by_etype_id[eid].to(device), num_nbr=self._num_neighbors_per_hop, # _sample_one_hop expects None for homogeneous graphs, not the PPR sentinel. - etype=( - self._etype_id_to_etype[eid] - if self._etype_id_to_etype[eid] != _PPR_HOMOGENEOUS_EDGE_TYPE - else None - ), + etype=None if etype == _PPR_HOMOGENEOUS_EDGE_TYPE else etype, ) - for eid in eids - ] - ) + ) + outputs: list[NeighborOutput] = await asyncio.gather(*sample_tasks) return { eid: (nodes_by_etype_id[eid], output.nbr, output.nbr_num) for eid, output in zip(eids, outputs) diff --git a/gigl/distributed/distributed_neighborloader.py b/gigl/distributed/distributed_neighborloader.py index 3d6d5a34b..f209887f2 100644 --- a/gigl/distributed/distributed_neighborloader.py +++ b/gigl/distributed/distributed_neighborloader.py @@ -24,6 +24,7 @@ ) from gigl.distributed.dist_sampling_producer import DistSamplingProducer from gigl.distributed.graph_store.remote_dist_dataset import RemoteDistDataset +from gigl.distributed.sampler import NODE_LABELS_METADATA_KEY from gigl.distributed.sampler_options import ( PPRSamplerOptions, SamplerOptions, @@ -558,6 +559,11 @@ def _collate_fn(self, msg: SampleMessage) -> Union[Data, HeteroData]: if isinstance(data, HeteroData): data = strip_non_ppr_edge_types(data, set(ppr_edge_indices.keys())) + # GLT truncates multi-column node labels to a single column (nlabels.T[0]). + # The sampler stashes the full label tensor in metadata so we can restore it here. + if NODE_LABELS_METADATA_KEY in metadata: + data.y = metadata.pop(NODE_LABELS_METADATA_KEY) + # Attach any remaining metadata (e.g. custom user-defined keys) directly onto the # data object so downstream code can access them via attribute lookup. for key, value in metadata.items(): diff --git a/gigl/distributed/sampler.py b/gigl/distributed/sampler.py index e99dd65dc..f3322ddff 100644 --- a/gigl/distributed/sampler.py +++ b/gigl/distributed/sampler.py @@ -8,6 +8,10 @@ POSITIVE_LABEL_METADATA_KEY: Final[str] = "gigl_positive_labels." NEGATIVE_LABEL_METADATA_KEY: Final[str] = "gigl_negative_labels." +# Used to pass the full multi-column node label tensor through sampler metadata so +# that DistNeighborLoader._collate_fn can replace the single-column data.y that +# GLT's sampler produces (GLT truncates to nlabels.T[0] for homogeneous graphs). +NODE_LABELS_METADATA_KEY: Final[str] = "gigl_node_labels." class ABLPNodeSamplerInput(NodeSamplerInput): diff --git a/gigl/distributed/utils/dist_sampler.py b/gigl/distributed/utils/dist_sampler.py index d42c5b104..0333f4138 100644 --- a/gigl/distributed/utils/dist_sampler.py +++ b/gigl/distributed/utils/dist_sampler.py @@ -82,6 +82,7 @@ def create_dist_sampler( alpha=sampler_options.alpha, eps=sampler_options.eps, max_ppr_nodes=sampler_options.max_ppr_nodes, + max_fetch_iterations=sampler_options.max_fetch_iterations, num_neighbors_per_hop=sampler_options.num_neighbors_per_hop, total_degree_dtype=sampler_options.total_degree_dtype, degree_tensors=degree_tensors, diff --git a/gigl/distributed/utils/neighborloader.py b/gigl/distributed/utils/neighborloader.py index bac714738..b91b411e3 100644 --- a/gigl/distributed/utils/neighborloader.py +++ b/gigl/distributed/utils/neighborloader.py @@ -190,8 +190,9 @@ def strip_non_ppr_edge_types( for edge_type in list(data.edge_types): if edge_type not in ppr_edge_types: del data[edge_type] - # num_sampled_edges may not exist at all (e.g. in tests or when GLT doesn't - # populate it), and may lack entries for edge types with zero samples. + # num_sampled_edges is set by GLT's standard k-hop sampler but not + # by PPR sampling, which constructs HeteroData manually. Guard with + # hasattr rather than assuming it's always present. if hasattr(data, "num_sampled_edges"): data.num_sampled_edges.pop(edge_type, None) return data From 0a468c09cf95ab042999b93524f72e48d6b1f5eb Mon Sep 17 00:00:00 2001 From: mkolodner Date: Thu, 30 Apr 2026 21:48:01 +0000 Subject: [PATCH 138/148] Update --- gigl/distributed/base_sampler.py | 43 ------------------- gigl/distributed/dist_neighbor_sampler.py | 9 ---- .../distributed/distributed_neighborloader.py | 6 --- gigl/distributed/sampler.py | 4 -- 4 files changed, 62 deletions(-) diff --git a/gigl/distributed/base_sampler.py b/gigl/distributed/base_sampler.py index edb1731eb..c0242c997 100644 --- a/gigl/distributed/base_sampler.py +++ b/gigl/distributed/base_sampler.py @@ -4,8 +4,6 @@ import torch from graphlearn_torch.distributed import DistNeighborSampler as GLTDistNeighborSampler -from graphlearn_torch.distributed.dist_feature import DistFeature -from graphlearn_torch.distributed.event_loop import wrap_torch_future from graphlearn_torch.sampler import ( HeteroSamplerOutput, NodeSamplerInput, @@ -15,7 +13,6 @@ from gigl.distributed.sampler import ( NEGATIVE_LABEL_METADATA_KEY, - NODE_LABELS_METADATA_KEY, POSITIVE_LABEL_METADATA_KEY, ABLPNodeSamplerInput, ) @@ -197,46 +194,6 @@ def _prepare_ablp_inputs( metadata=metadata, ) - async def _attach_full_node_labels_to_metadata( - self, - all_sampled_nodes: torch.Tensor, - metadata: dict[str, torch.Tensor], - ) -> None: - """Fetch all node label columns and stash them in sampler metadata. - - GLT's sampler truncates node labels to a single column (``nlabels.T[0]``) - before assembling the SampleMessage, so ``data.y`` only ever carries the - first label column. This method fetches the full label tensor for all - sampled nodes and stores it in *metadata* under ``NODE_LABELS_METADATA_KEY`` - so that ``DistNeighborLoader._collate_fn`` can replace the truncated - ``data.y`` with the complete multi-column tensor. - - Only has an effect when: - - ``self.dist_node_labels`` is a ``DistFeature`` (i.e., the dataset has - node labels), and - - the fetched label tensor has more than one column (multi-label case). - - For single-label datasets the method is a no-op, and GLT's existing - label path is used unchanged. - - This method supports homogeneous graphs only. Heterogeneous multi-label - support can be added here if needed in the future. - - Args: - all_sampled_nodes: 1-D tensor of global node IDs for all nodes in the - sampled subgraph (``SamplerOutput.node`` for the homogeneous case). - metadata: The metadata dict that will be attached to ``SamplerOutput``. - Modified in-place. - """ - if self.dist_node_labels is None: - return - if not isinstance(self.dist_node_labels, DistFeature): - return - fut = self.dist_node_labels.async_get(all_sampled_nodes) - full_labels: torch.Tensor = await wrap_torch_future(fut) - if full_labels.ndim == 2 and full_labels.shape[1] > 1: - metadata[NODE_LABELS_METADATA_KEY] = full_labels - async def _sample_from_nodes( self, inputs: NodeSamplerInput, diff --git a/gigl/distributed/dist_neighbor_sampler.py b/gigl/distributed/dist_neighbor_sampler.py index c67744506..a91737b5b 100644 --- a/gigl/distributed/dist_neighbor_sampler.py +++ b/gigl/distributed/dist_neighbor_sampler.py @@ -185,13 +185,4 @@ async def _sample_from_nodes( ) self.inducer_pool.put(inducer) - - # For homogeneous graphs with multi-column node labels, stash the full label - # tensor in metadata so _collate_fn can restore it after GLT truncates data.y. - if not is_hetero: - await self._attach_full_node_labels_to_metadata( - all_sampled_nodes=sample_output.node, - metadata=metadata, - ) - return sample_output diff --git a/gigl/distributed/distributed_neighborloader.py b/gigl/distributed/distributed_neighborloader.py index f209887f2..3d6d5a34b 100644 --- a/gigl/distributed/distributed_neighborloader.py +++ b/gigl/distributed/distributed_neighborloader.py @@ -24,7 +24,6 @@ ) from gigl.distributed.dist_sampling_producer import DistSamplingProducer from gigl.distributed.graph_store.remote_dist_dataset import RemoteDistDataset -from gigl.distributed.sampler import NODE_LABELS_METADATA_KEY from gigl.distributed.sampler_options import ( PPRSamplerOptions, SamplerOptions, @@ -559,11 +558,6 @@ def _collate_fn(self, msg: SampleMessage) -> Union[Data, HeteroData]: if isinstance(data, HeteroData): data = strip_non_ppr_edge_types(data, set(ppr_edge_indices.keys())) - # GLT truncates multi-column node labels to a single column (nlabels.T[0]). - # The sampler stashes the full label tensor in metadata so we can restore it here. - if NODE_LABELS_METADATA_KEY in metadata: - data.y = metadata.pop(NODE_LABELS_METADATA_KEY) - # Attach any remaining metadata (e.g. custom user-defined keys) directly onto the # data object so downstream code can access them via attribute lookup. for key, value in metadata.items(): diff --git a/gigl/distributed/sampler.py b/gigl/distributed/sampler.py index f3322ddff..e99dd65dc 100644 --- a/gigl/distributed/sampler.py +++ b/gigl/distributed/sampler.py @@ -8,10 +8,6 @@ POSITIVE_LABEL_METADATA_KEY: Final[str] = "gigl_positive_labels." NEGATIVE_LABEL_METADATA_KEY: Final[str] = "gigl_negative_labels." -# Used to pass the full multi-column node label tensor through sampler metadata so -# that DistNeighborLoader._collate_fn can replace the single-column data.y that -# GLT's sampler produces (GLT truncates to nlabels.T[0] for homogeneous graphs). -NODE_LABELS_METADATA_KEY: Final[str] = "gigl_node_labels." class ABLPNodeSamplerInput(NodeSamplerInput): From 65a1590f109a6a7382d1ff55d9ef5219110c71f7 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 1 May 2026 23:33:55 +0000 Subject: [PATCH 139/148] Address comments --- Makefile | 4 +- gigl-core/Makefile | 6 +- gigl-core/core/sampling/ppr_forward_push.cpp | 234 +++++++++--------- gigl-core/core/sampling/ppr_forward_push.h | 34 +-- .../core/sampling/python_ppr_forward_push.cpp | 27 +- gigl/distributed/dist_ppr_sampler.py | 32 ++- .../unit/distributed/dist_ppr_sampler_test.py | 38 ++- 7 files changed, 198 insertions(+), 177 deletions(-) diff --git a/Makefile b/Makefile index 9dc8212d9..06752d5af 100644 --- a/Makefile +++ b/Makefile @@ -166,7 +166,7 @@ build_cpp_extensions: $(MAKE) -C gigl-core build_cpp_extensions check_lint_cpp: build_cpp_extensions - $(if $(CPP_SOURCES_NO_CUDA),uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA)) + uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA) # Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, # changes expressions, adds/removes keywords), not just style. Run manually and @@ -178,7 +178,7 @@ check_lint_cpp: build_cpp_extensions # WarningsAsErrors: '*', so the warning must be silenced at the compiler level before # clang-tidy ever sees it. fix_lint_cpp: build_cpp_extensions - $(if $(CPP_SOURCES_NO_CUDA),clang-tidy-15 --fix --extra-arg=-Wno-ignored-optimization-argument -p gigl-core/.cache/cmake_build/compile_commands.json $(CPP_SOURCES_NO_CUDA)) + clang-tidy-15 --fix --extra-arg=-Wno-ignored-optimization-argument -p gigl-core/.cache/cmake_build/compile_commands.json $(CPP_SOURCES_NO_CUDA) lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" diff --git a/gigl-core/Makefile b/gigl-core/Makefile index 572799dff..949db19ac 100644 --- a/gigl-core/Makefile +++ b/gigl-core/Makefile @@ -25,13 +25,11 @@ unit_test_cpp: .cache/cpp_tests/.configured cmake --build .cache/cpp_tests --parallel ctest --test-dir .cache/cpp_tests --output-on-failure -# TODO: Remove the $(if ...) guards once C++ source files are permanently present in the -# repo. The guards exist to silently no-op on branches that have no python_*.cpp files yet. check_format_cpp: - $(if $(CPP_SOURCES),clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES)) + clang-format-15 --dry-run --Werror --style=file $(CPP_SOURCES) format_cpp: - $(if $(CPP_SOURCES),clang-format-15 -i --style=file $(CPP_SOURCES)) + clang-format-15 -i --style=file $(CPP_SOURCES) # Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent # after switching between branches with substantially different CMakeLists.txt structure. diff --git a/gigl-core/core/sampling/ppr_forward_push.cpp b/gigl-core/core/sampling/ppr_forward_push.cpp index 06545f58e..8abb1a25f 100644 --- a/gigl-core/core/sampling/ppr_forward_push.cpp +++ b/gigl-core/core/sampling/ppr_forward_push.cpp @@ -14,9 +14,9 @@ namespace gigl { // Pack (node_id, etype_id) into a single uint64 for use as a hash key. // Inputs are cast through uint32_t to avoid sign-extension of negative int32 values. -static uint64_t packKey(int32_t nodeId, int32_t etypeId) { +static uint64_t packKey(int32_t nodeId, int32_t edgeTypeId) { return (static_cast(static_cast(nodeId)) << 32) | - static_cast(etypeId); + static_cast(edgeTypeId); } PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, @@ -44,42 +44,39 @@ PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, TORCH_CHECK(seedNodeTypeId < _numNodeTypes, "seedNodeTypeId ", seedNodeTypeId, " out of range [0, ", _numNodeTypes, ")."); auto numEdgeTypes = static_cast(_edgeTypeToDstNtypeId.size()); - for (int32_t eid = 0; eid < numEdgeTypes; ++eid) { - int32_t dstNt = _edgeTypeToDstNtypeId[eid]; - TORCH_CHECK(dstNt >= 0, - "edgeTypeToDstNtypeId[", eid, "] = ", dstNt, " is negative."); - TORCH_CHECK(dstNt < _numNodeTypes, - "edgeTypeToDstNtypeId[", eid, "] = ", dstNt, + for (int32_t edgeTypeId = 0; edgeTypeId < numEdgeTypes; ++edgeTypeId) { + int32_t dstNodeTypeId = _edgeTypeToDstNtypeId[edgeTypeId]; + TORCH_CHECK(dstNodeTypeId >= 0, + "edgeTypeToDstNtypeId[", edgeTypeId, "] = ", dstNodeTypeId, " is negative."); + TORCH_CHECK(dstNodeTypeId < _numNodeTypes, + "edgeTypeToDstNtypeId[", edgeTypeId, "] = ", dstNodeTypeId, " out of range [0, ", _numNodeTypes, ")."); } - for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { - for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { - TORCH_CHECK(eid >= 0, - "nodeTypeToEdgeTypeIds[", nt, "] contains negative edge type id ", eid, "."); - TORCH_CHECK(eid < numEdgeTypes, - "nodeTypeToEdgeTypeIds[", nt, "] contains edge type id ", eid, + for (int32_t nodeTypeId = 0; nodeTypeId < _numNodeTypes; ++nodeTypeId) { + for (int32_t edgeTypeId : _nodeTypeToEdgeTypeIds[nodeTypeId]) { + TORCH_CHECK(edgeTypeId >= 0, + "nodeTypeToEdgeTypeIds[", nodeTypeId, "] contains negative edge type id ", edgeTypeId, "."); + TORCH_CHECK(edgeTypeId < numEdgeTypes, + "nodeTypeToEdgeTypeIds[", nodeTypeId, "] contains edge type id ", edgeTypeId, " out of range [0, ", numEdgeTypes, ")."); } } - // Allocate per-seed, per-node-type tables. - // .assign(n, val) fills a vector with n copies of val — like [val] * n in Python. - _pprScores.assign(_batchSize, std::vector>(_numNodeTypes)); - _residuals.assign(_batchSize, std::vector>(_numNodeTypes)); - _queue.assign(_batchSize, std::vector>(_numNodeTypes)); - _queuedNodes.assign(_batchSize, std::vector>(_numNodeTypes)); + // Allocate per-seed, per-node-type state. + // .assign(n, val) fills a vector with n independent copies of val — like [val for _ in range(n)] in Python. + _state.assign(_batchSize, std::vector(_numNodeTypes)); // accessor() returns a typed view into the tensor's data that // supports [i] indexing with bounds checking in debug builds. - auto acc = seedNodes.accessor(); + auto seedNodeAcc = seedNodes.accessor(); _numNodesInQueue = _batchSize; - for (int32_t i = 0; i < _batchSize; ++i) { - auto seed = static_cast(acc[i]); + for (int32_t seedIdx = 0; seedIdx < _batchSize; ++seedIdx) { + auto seedNodeId = static_cast(seedNodeAcc[seedIdx]); // PPR initialisation: each seed starts with residual = alpha (the // restart probability). The first push will move alpha into ppr_score // and distribute (1-alpha)*alpha to the seed's neighbors. - _residuals[i][seedNodeTypeId][seed] = _alpha; - _queue[i][seedNodeTypeId].insert(seed); + _state[seedIdx][seedNodeTypeId].residuals[seedNodeId] = _alpha; + _state[seedIdx][seedNodeTypeId].queue.insert(seedNodeId); } } @@ -91,37 +88,38 @@ std::optional> PPRForwardPushState::d // Reset the snapshot from the previous iteration. // TODO: if this loop becomes a bottleneck, consider parallelising with // std::for_each(std::execution::par_unseq, ...) or adding vectorisation hints. - for (int32_t s = 0; s < _batchSize; ++s) { - for (auto& qs : _queuedNodes[s]) { - qs.clear(); + for (auto& perSeedState : _state) { + for (auto& nodeTypeState : perSeedState) { + nodeTypeState.queuedNodes.clear(); } } - // nodesToLookup[eid] = set of node IDs that need a neighbor fetch for - // edge type eid this round. Using a set deduplicates nodes that appear + // nodesToLookup[edgeTypeId] = set of node IDs that need a neighbor fetch for + // edge type edgeTypeId this round. Using a set deduplicates nodes that appear // in multiple seeds' queues: we only fetch each (node, etype) pair once. std::unordered_map> nodesToLookup; int32_t totalDrainedThisRound = 0; - for (int32_t s = 0; s < _batchSize; ++s) { - for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { - if (_queue[s][nt].empty()) { + for (int32_t seedIdx = 0; seedIdx < _batchSize; ++seedIdx) { + for (int32_t nodeTypeId = 0; nodeTypeId < _numNodeTypes; ++nodeTypeId) { + auto& seedNodeTypeState = _state[seedIdx][nodeTypeId]; + if (seedNodeTypeState.queue.empty()) { continue; } // Move the live queue into the snapshot in O(1) — avoids copying all node IDs. // The explicit clear() after move is defensive: the standard only guarantees // a moved-from container is "valid but unspecified", not necessarily empty. - _queuedNodes[s][nt] = std::move(_queue[s][nt]); - _queue[s][nt].clear(); - auto numDrained = static_cast(_queuedNodes[s][nt].size()); + seedNodeTypeState.queuedNodes = std::move(seedNodeTypeState.queue); + seedNodeTypeState.queue.clear(); + auto numDrained = static_cast(seedNodeTypeState.queuedNodes.size()); totalDrainedThisRound += numDrained; _numNodesInQueue -= numDrained; - for (int32_t nodeId : _queuedNodes[s][nt]) { - for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { - if (_neighborCache.find(packKey(nodeId, eid)) == _neighborCache.end()) { - nodesToLookup[eid].insert(nodeId); + for (int32_t nodeId : seedNodeTypeState.queuedNodes) { + for (int32_t edgeTypeId : _nodeTypeToEdgeTypeIds[nodeTypeId]) { + if (_neighborCache.find(packKey(nodeId, edgeTypeId)) == _neighborCache.end()) { + nodesToLookup[edgeTypeId].insert(nodeId); } } } @@ -131,9 +129,9 @@ std::optional> PPRForwardPushState::d _nodesDrainedPerIteration.push_back(totalDrainedThisRound); std::unordered_map result; - for (const auto& [eid, nodeSet] : nodesToLookup) { - std::vector ids(nodeSet.begin(), nodeSet.end()); - result[eid] = torch::tensor(ids, torch::kLong); + for (const auto& [edgeTypeId, nodeSet] : nodesToLookup) { + std::vector nodeIdsToLookup(nodeSet.begin(), nodeSet.end()); + result[edgeTypeId] = torch::tensor(nodeIdsToLookup, torch::kLong); } return result; } @@ -144,31 +142,31 @@ const std::vector& PPRForwardPushState::getNodesDrainedPerIteration() c void PPRForwardPushState::pushResiduals( const std::unordered_map>& fetchedByEtypeId) { - // Step 1: Unpack the input map into a C++ map keyed by packKey(nodeId, etypeId) + // Step 1: Unpack the input map into a C++ map keyed by packKey(nodeId, edgeTypeId) // for fast lookup during the residual-push loop below. std::unordered_map> fetched; - for (const auto& [eid, tup] : fetchedByEtypeId) { - const auto& nodeIdsT = std::get<0>(tup); - const auto& flatNbrsT = std::get<1>(tup); - const auto& countsT = std::get<2>(tup); + for (const auto& [edgeTypeId, neighborTensors] : fetchedByEtypeId) { + const auto& nodeIdsTensor = std::get<0>(neighborTensors); + const auto& flatNeighborIdsTensor = std::get<1>(neighborTensors); + const auto& countsTensor = std::get<2>(neighborTensors); // accessor() gives a bounds-checked, typed 1-D view into // each tensor's data — equivalent to iterating over a NumPy array. - auto nodeAcc = nodeIdsT.accessor(); - auto nbrAcc = flatNbrsT.accessor(); - auto cntAcc = countsT.accessor(); + auto nodeIdsAccessor = nodeIdsTensor.accessor(); + auto flatNeighborIdsAccessor = flatNeighborIdsTensor.accessor(); + auto countsAccessor = countsTensor.accessor(); // Walk the flat neighbor list, slicing out each node's neighbors using // the running offset into the concatenated flat buffer. int64_t offset = 0; - for (int64_t i = 0; i < nodeIdsT.size(0); ++i) { - auto nid = static_cast(nodeAcc[i]); - int64_t count = cntAcc[i]; - std::vector nbrs(count); - for (int64_t j = 0; j < count; ++j) { - nbrs[j] = static_cast(nbrAcc[offset + j]); + for (int64_t nodeIdx = 0; nodeIdx < nodeIdsTensor.size(0); ++nodeIdx) { + auto nodeId = static_cast(nodeIdsAccessor[nodeIdx]); + int64_t count = countsAccessor[nodeIdx]; + std::vector neighborIds(count); + for (int64_t neighborIdx = 0; neighborIdx < count; ++neighborIdx) { + neighborIds[neighborIdx] = static_cast(flatNeighborIdsAccessor[offset + neighborIdx]); } - fetched[packKey(nid, eid)] = std::move(nbrs); + fetched[packKey(nodeId, edgeTypeId)] = std::move(neighborIds); offset += count; } } @@ -178,20 +176,20 @@ void PPRForwardPushState::pushResiduals( // a. Absorb residual into the PPR score. // b. Distribute (1-alpha) * residual equally to each neighbor. // c. Enqueue any neighbor whose residual now exceeds the requeue threshold. - for (int32_t s = 0; s < _batchSize; ++s) { - for (int32_t nt = 0; nt < _numNodeTypes; ++nt) { - if (_queuedNodes[s][nt].empty()) { + for (int32_t seedIdx = 0; seedIdx < _batchSize; ++seedIdx) { + for (int32_t nodeTypeId = 0; nodeTypeId < _numNodeTypes; ++nodeTypeId) { + auto& srcNodeTypeState = _state[seedIdx][nodeTypeId]; + if (srcNodeTypeState.queuedNodes.empty()) { continue; } - for (int32_t src : _queuedNodes[s][nt]) { - auto& srcRes = _residuals[s][nt]; - auto it = srcRes.find(src); - double res = (it != srcRes.end()) ? it->second : 0.0; + for (int32_t sourceNodeId : srcNodeTypeState.queuedNodes) { + auto residualIter = srcNodeTypeState.residuals.find(sourceNodeId); + double sourceResidual = (residualIter != srcNodeTypeState.residuals.end()) ? residualIter->second : 0.0; // a. Absorb: move residual into the PPR score. - _pprScores[s][nt][src] += res; - srcRes[src] = 0.0; + srcNodeTypeState.pprScores[sourceNodeId] += sourceResidual; + srcNodeTypeState.residuals[sourceNodeId] = 0.0; // b. Count total fetched/cached neighbors across all edge types for // this source node. We normalise by the number of neighbors we @@ -199,12 +197,12 @@ void PPRForwardPushState::pushResiduals( // distributed among known neighbors rather than leaking to unfetched // ones (which matters when num_neighbors_per_hop < true_degree). int32_t totalFetched = 0; - for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { - auto fetchedEntry = fetched.find(packKey(src, eid)); + for (int32_t edgeTypeId : _nodeTypeToEdgeTypeIds[nodeTypeId]) { + auto fetchedEntry = fetched.find(packKey(sourceNodeId, edgeTypeId)); if (fetchedEntry != fetched.end()) { totalFetched += static_cast(fetchedEntry->second.size()); } else { - auto cachedEntry = _neighborCache.find(packKey(src, eid)); + auto cachedEntry = _neighborCache.find(packKey(sourceNodeId, edgeTypeId)); if (cachedEntry != _neighborCache.end()) { totalFetched += static_cast(cachedEntry->second.size()); } @@ -221,53 +219,53 @@ void PPRForwardPushState::pushResiduals( continue; } - double resPerNbr = (1.0 - _alpha) * res / static_cast(totalFetched); + double residualPerNeighbor = (1.0 - _alpha) * sourceResidual / static_cast(totalFetched); - for (int32_t eid : _nodeTypeToEdgeTypeIds[nt]) { + for (int32_t edgeTypeId : _nodeTypeToEdgeTypeIds[nodeTypeId]) { // Invariant: fetched and _neighborCache are mutually exclusive for // any given (node, etype) key within one iteration. drainQueue() // only requests a fetch for nodes absent from _neighborCache, so a // key is in at most one of the two. - // Points at the neighbor list we will distribute residual to — + // Neighbor list for this (src, edgeTypeId) pair, if one exists — // either from `fetched` (new this iteration) or `_neighborCache` - // (seen in a previous iteration). Null if neither has data for - // this (node, etype) pair. Does not own any memory. - const std::vector* nbrList = nullptr; - auto fetchedEntry = fetched.find(packKey(src, eid)); + // (seen in a previous iteration). + std::optional>> neighborList; + auto fetchedEntry = fetched.find(packKey(sourceNodeId, edgeTypeId)); if (fetchedEntry != fetched.end()) { - nbrList = &fetchedEntry->second; + neighborList = std::cref(fetchedEntry->second); } else { - auto cachedEntry = _neighborCache.find(packKey(src, eid)); + auto cachedEntry = _neighborCache.find(packKey(sourceNodeId, edgeTypeId)); if (cachedEntry != _neighborCache.end()) { - nbrList = &cachedEntry->second; + neighborList = std::cref(cachedEntry->second); } } - if (!nbrList || nbrList->empty()) { + if (!neighborList || neighborList->get().empty()) { continue; } - int32_t dstNt = _edgeTypeToDstNtypeId[eid]; + int32_t dstNodeTypeId = _edgeTypeToDstNtypeId[edgeTypeId]; // c. Accumulate residual for each neighbor and re-enqueue if threshold // exceeded. - for (int32_t nbr : *nbrList) { - _residuals[s][dstNt][nbr] += resPerNbr; + auto& dstNodeTypeState = _state[seedIdx][dstNodeTypeId]; + for (int32_t neighborNodeId : neighborList->get()) { + dstNodeTypeState.residuals[neighborNodeId] += residualPerNeighbor; - double threshold = _requeueThresholdFactor * static_cast(getTotalDegree(nbr, dstNt)); + double threshold = _requeueThresholdFactor * static_cast(getTotalDegree(neighborNodeId, dstNodeTypeId)); - if (_queue[s][dstNt].find(nbr) == _queue[s][dstNt].end() && - _residuals[s][dstNt][nbr] >= threshold) { - _queue[s][dstNt].insert(nbr); + if (dstNodeTypeState.queue.find(neighborNodeId) == dstNodeTypeState.queue.end() && + dstNodeTypeState.residuals[neighborNodeId] >= threshold) { + dstNodeTypeState.queue.insert(neighborNodeId); ++_numNodesInQueue; // Promote neighbor lists to the persistent cache: this node will // be processed next iteration, so caching avoids a re-fetch. - for (int32_t peid : _nodeTypeToEdgeTypeIds[dstNt]) { - uint64_t pk = packKey(nbr, peid); - if (_neighborCache.find(pk) == _neighborCache.end()) { - auto fetchedNbrEntry = fetched.find(pk); - if (fetchedNbrEntry != fetched.end()) { - _neighborCache[pk] = fetchedNbrEntry->second; + for (int32_t neighborEdgeTypeId : _nodeTypeToEdgeTypeIds[dstNodeTypeId]) { + uint64_t packedKey = packKey(neighborNodeId, neighborEdgeTypeId); + if (_neighborCache.find(packedKey) == _neighborCache.end()) { + auto fetchedNeighborEntry = fetched.find(packedKey); + if (fetchedNeighborEntry != fetched.end()) { + _neighborCache[packedKey] = fetchedNeighborEntry->second; } } } @@ -285,57 +283,57 @@ std::unordered_map flatIds; - std::vector flatWeights; + std::vector flatWeights; std::vector validCounts; for (int32_t seedIdx = 0; seedIdx < _batchSize; ++seedIdx) { - const auto& scores = _pprScores[seedIdx][nt]; + const auto& scores = _state[seedIdx][nodeTypeId].pprScores; int32_t topK = std::min(maxPprNodes, static_cast(scores.size())); if (topK > 0) { std::vector> scorePairs(scores.begin(), scores.end()); std::partial_sort(scorePairs.begin(), scorePairs.begin() + topK, scorePairs.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); - for (int32_t i = 0; i < topK; ++i) { - flatIds.push_back(static_cast(scorePairs[i].first)); - // Cast to float32 for output; internal scores stay double to - // avoid accumulated rounding errors in the push loop. - flatWeights.push_back(static_cast(scorePairs[i].second)); + for (int32_t rankIdx = 0; rankIdx < topK; ++rankIdx) { + flatIds.push_back(static_cast(scorePairs[rankIdx].first)); + flatWeights.push_back(scorePairs[rankIdx].second); } } validCounts.push_back(static_cast(topK)); } - result[nt] = {torch::tensor(flatIds, torch::kLong), - torch::tensor(flatWeights, torch::kFloat), - torch::tensor(validCounts, torch::kLong)}; + result[nodeTypeId] = {torch::tensor(flatIds, torch::kLong), + torch::tensor(flatWeights, torch::kDouble), + torch::tensor(validCounts, torch::kLong)}; } return result; } -int32_t PPRForwardPushState::getTotalDegree(int32_t nodeId, int32_t ntypeId) const { - if (ntypeId >= static_cast(_degreeTensors.size())) { - return 0; - } - const auto& t = _degreeTensors[ntypeId]; - if (t.numel() == 0) { +int32_t PPRForwardPushState::getTotalDegree(int32_t nodeId, int32_t nodeTypeId) const { + TORCH_CHECK(nodeTypeId >= 0, + "nodeTypeId ", nodeTypeId, " is negative, which indicates a sampler bug."); + TORCH_CHECK(nodeTypeId < static_cast(_degreeTensors.size()), + "nodeTypeId ", nodeTypeId, " out of range [0, ", _degreeTensors.size(), + "). This indicates a construction bug in the sampler."); + const auto& degreeTensor = _degreeTensors[nodeTypeId]; + if (degreeTensor.numel() == 0) { return 0; } TORCH_CHECK(nodeId >= 0, "Node ID ", nodeId, " is negative, which indicates a sampler bug."); - TORCH_CHECK(nodeId < static_cast(t.size(0)), + TORCH_CHECK(nodeId < static_cast(degreeTensor.size(0)), "Node ID ", nodeId, " out of range for degree tensor of ntype_id ", - ntypeId, " (size=", t.size(0), "). This indicates corrupted graph data or a sampler bug."); - if (t.scalar_type() == torch::kInt) { - return t.data_ptr()[nodeId]; + nodeTypeId, " (size=", degreeTensor.size(0), "). This indicates corrupted graph data or a sampler bug."); + if (degreeTensor.scalar_type() == torch::kInt) { + return degreeTensor.data_ptr()[nodeId]; } - if (t.scalar_type() == torch::kLong) { + if (degreeTensor.scalar_type() == torch::kLong) { return static_cast( - std::min(t.data_ptr()[nodeId], INT32_MAX)); + std::min(degreeTensor.data_ptr()[nodeId], INT32_MAX)); } - TORCH_CHECK(false, "Unsupported degree tensor dtype: ", t.scalar_type(), + TORCH_CHECK(false, "Unsupported degree tensor dtype: ", degreeTensor.scalar_type(), ". Expected torch.int32 or torch.int64."); return 0; // unreachable; suppresses compiler warning } diff --git a/gigl-core/core/sampling/ppr_forward_push.h b/gigl-core/core/sampling/ppr_forward_push.h index 003afca3b..694f37c59 100644 --- a/gigl-core/core/sampling/ppr_forward_push.h +++ b/gigl-core/core/sampling/ppr_forward_push.h @@ -12,6 +12,18 @@ namespace gigl { +// Per-seed, per-node-type PPR algorithm state. +// Grouping all four tables into one struct keeps related data co-located in memory: +// when the push loop accesses pprScores, residuals, queue, and queuedNodes for the +// same (seed, ntype) pair, they are in the same cache line region rather than spread +// across four separate top-level vectors. +struct SeedNodeTypeState { + std::unordered_map pprScores; // absorbed PPR mass + std::unordered_map residuals; // unabsorbed mass waiting to push + std::unordered_set queue; // nodes queued for the next drain + std::unordered_set queuedNodes; // snapshot captured by drainQueue() +}; + // C++ kernel for PPR Forward Push (Andersen et al., 2006). // Hot-loop state lives here; distributed neighbor fetches are driven from Python. // @@ -54,7 +66,7 @@ class PPRForwardPushState { private: // Total out-degree of a node across all edge types. Returns 0 for sink nodes. - [[nodiscard]] int32_t getTotalDegree(int32_t nodeId, int32_t ntypeId) const; + [[nodiscard]] int32_t getTotalDegree(int32_t nodeId, int32_t nodeTypeId) const; double _alpha; double _requeueThresholdFactor; // alpha * eps; per-node requeue threshold = factor * degree @@ -71,28 +83,18 @@ class PPRForwardPushState { std::vector _edgeTypeToDstNtypeId; std::vector _degreeTensors; - // Per-seed, per-node-type PPR state. All four tables share the same nesting: + // Per-seed, per-node-type PPR state. Indexed as _state[seedIdx][nodeTypeId]. // // outer vector [_batchSize] — one entry per seed node in the batch - // inner vector [_numNodeTypes] — one entry per node type in the graph - // map / set {node_id → …} — only nodes reached during the walk are present + // inner vector [_numNodeTypes] — one SeedNodeTypeState per node type // // int32_t is used for node and type IDs throughout to match PyG/GLT's signed-integer // convention (torch.int32 / torch.int64). Signed types also make nodeId >= 0 checks // meaningful — an unsigned type would make that guard tautological. // - // All four tables are sized [_batchSize][_numNodeTypes] at construction and never - // resized, so [seedIdx][nt] indexing is always safe within the loop bounds. - // - // _pprScores: absorbed PPR mass — the final output scores written by pushResiduals(). - // _residuals: unabsorbed mass waiting to be pushed to neighbors. - // _queue: nodes whose residual exceeds the requeue threshold; drained each iteration. - // _queuedNodes: snapshot of _queue captured by drainQueue() so pushResiduals() knows - // which nodes to process in the current iteration. - std::vector>> _pprScores; - std::vector>> _residuals; - std::vector>> _queue; - std::vector>> _queuedNodes; + // Sized [_batchSize][_numNodeTypes] at construction and never resized, + // so [seedIdx][nodeTypeId] indexing is always safe within the loop bounds. + std::vector> _state; // Neighbor lists fetched from the distributed graph store, keyed by packKey(node_id, etype_id). // Populated incrementally as nodes are processed; avoids re-fetching the same node twice. diff --git a/gigl-core/core/sampling/python_ppr_forward_push.cpp b/gigl-core/core/sampling/python_ppr_forward_push.cpp index fc1c187a6..300528afc 100644 --- a/gigl-core/core/sampling/python_ppr_forward_push.cpp +++ b/gigl-core/core/sampling/python_ppr_forward_push.cpp @@ -14,32 +14,37 @@ #include "ppr_forward_push.h" namespace py = pybind11; -using gigl::PPRForwardPushState; + +namespace gigl { // pushResiduals: a wrapper is needed solely to release the GIL during the C++ push. // pybind11/stl.h handles all type conversions automatically; the other methods use // direct member function pointers for the same reason. static void pushResidualsWrapper(PPRForwardPushState& state, const py::dict& fetchedByEtypeId) { - std::unordered_map> cppMap; + std::unordered_map> neighborTensorsByEtypeId; // Dict iteration touches Python objects — GIL must be held here. for (auto item : fetchedByEtypeId) { - auto eid = item.first.cast(); - auto tup = item.second.cast(); - cppMap[eid] = {tup[0].cast(), tup[1].cast(), tup[2].cast()}; + auto edgeTypeId = item.first.cast(); + auto neighborTensors = item.second.cast(); + neighborTensorsByEtypeId[edgeTypeId] = {neighborTensors[0].cast(), + neighborTensors[1].cast(), + neighborTensors[2].cast()}; } // C++ push only uses tensor accessor/data_ptr APIs — GIL-safe to release. // Releasing here lets the asyncio event loop process RPC completion callbacks // from other concurrent PPR coroutines while this push runs. { py::gil_scoped_release release; - state.pushResiduals(cppMap); + state.pushResiduals(neighborTensorsByEtypeId); } } +} // namespace gigl + // TORCH_EXTENSION_NAME is set by PyTorch's build system to match the Python // module name derived from this file's path (e.g. "ppr_forward_push"). PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - py::class_(m, "PPRForwardPushState") + py::class_(m, "PPRForwardPushState") .def(py::init>, std::vector, std::vector>()) - .def("drain_queue", &PPRForwardPushState::drainQueue) - .def("push_residuals", pushResidualsWrapper) - .def("extract_top_k", &PPRForwardPushState::extractTopK) - .def("get_nodes_drained_per_iteration", &PPRForwardPushState::getNodesDrainedPerIteration); + .def("drain_queue", &gigl::PPRForwardPushState::drainQueue) + .def("push_residuals", gigl::pushResidualsWrapper) + .def("extract_top_k", &gigl::PPRForwardPushState::extractTopK) + .def("get_nodes_drained_per_iteration", &gigl::PPRForwardPushState::getNodesDrainedPerIteration); } diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index f7f3e41ba..e07e293c8 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -3,6 +3,8 @@ from typing import Optional, Union import torch +# TODO: Once gigl_core has a stable Python interface, re-export PPRForwardPushState +# under a gigl.core namespace rather than importing directly from the C++ extension. from gigl_core import PPRForwardPushState from graphlearn_torch.sampler import ( HeteroSamplerOutput, @@ -155,19 +157,15 @@ def __init__( # We include both source types (have outgoing edges) and destination-only # types (no outgoing edges, but may accumulate PPR score during the walk) # so the kernel can index residual/ppr_score tables for any node it sees. - all_node_types: list[NodeType] = sorted( - {nt for nt in self._node_type_to_edge_types} - | { - self._get_destination_type(et) - for etypes in self._node_type_to_edge_types.values() - for et in etypes - } - ) - # dict.fromkeys preserves insertion order while deduplicating. - all_edge_types: list[EdgeType] = list( - dict.fromkeys( - et for etypes in self._node_type_to_edge_types.values() for et in etypes - ) + source_node_types: set[NodeType] = set(self._node_type_to_edge_types.keys()) + destination_node_types: set[NodeType] = { + self._get_destination_type(et) + for etypes in self._node_type_to_edge_types.values() + for et in etypes + } + all_node_types: list[NodeType] = sorted(source_node_types | destination_node_types) + all_edge_types: list[EdgeType] = sorted( + {et for etypes in self._node_type_to_edge_types.values() for et in etypes} ) self._node_type_to_id: dict[NodeType, int] = { @@ -184,17 +182,17 @@ def __init__( self._etype_to_etype_id[et] for et in self._node_type_to_edge_types.get(nt, []) ] - for nt in _all_node_types + for nt in all_node_types ] self._edge_type_id_to_dst_ntype_id: list[int] = [ self._node_type_to_id[self._get_destination_type(et)] - for et in _all_edge_types + for et in all_edge_types ] # Degree tensors indexed by ntype_id. Destination-only types get an empty # tensor; the C++ kernel returns 0 for those, matching _get_total_degree. self._degree_tensors_for_cpp: list[torch.Tensor] = [ self._node_type_to_total_degree.get(nt, torch.zeros(0, dtype=torch.int32)) - for nt in _all_node_types + for nt in all_node_types ] def _build_total_degree_tensors( @@ -615,7 +613,7 @@ async def _sample_from_nodes( edge_index = torch.stack([rows, cols]) else: edge_index = torch.zeros(2, 0, dtype=torch.long, device=self.device) - flat_weights = torch.zeros(0, dtype=torch.float, device=self.device) + flat_weights = torch.zeros(0, dtype=torch.double, device=self.device) etype_str = repr(ppr_edge_type) metadata[f"{PPR_EDGE_INDEX_METADATA_KEY}{etype_str}"] = edge_index metadata[f"{PPR_WEIGHT_METADATA_KEY}{etype_str}"] = flat_weights diff --git a/tests/unit/distributed/dist_ppr_sampler_test.py b/tests/unit/distributed/dist_ppr_sampler_test.py index 20c743f66..3e81f8d37 100644 --- a/tests/unit/distributed/dist_ppr_sampler_test.py +++ b/tests/unit/distributed/dist_ppr_sampler_test.py @@ -270,9 +270,10 @@ def _assert_ppr_scores_match_reference( """Assert sampler PPR scores match reference scores per node type. Checks that top-k node sets are identical and that per-node scores - are within atol=1e-5. The forward push error per node is bounded by - O(alpha * eps * degree); for max degree 3, alpha=0.5, eps=1e-6 the - theoretical bound is ~1.5e-6, so 1e-5 provides a safety margin. + are within atol=2e-6. The forward push error per node is bounded by + the per-node requeue threshold alpha * eps * degree; for max degree 3, + alpha=0.5, eps=1e-6 the per-node threshold is ~1.5e-6. Tolerance is + set to 2e-6 to provide a small margin above this bound. Args: ntype_to_sampler_ppr: Sampler output from :func:`_extract_hetero_ppr_scores`. @@ -291,7 +292,7 @@ def _assert_ppr_scores_match_reference( for node_id in reference_ppr[ntype_str]: ref_score = reference_ppr[ntype_str][node_id] sam_score = ntype_to_sampler_ppr[ntype_str][node_id] - assert abs(sam_score - ref_score) < 1e-5, ( + assert abs(sam_score - ref_score) < 2e-6, ( f"{seed_id}, type {ntype_str}, node {node_id}: " f"sampler={sam_score:.8f} vs reference={ref_score:.8f}" ) @@ -329,6 +330,12 @@ def _run_ppr_loader_correctness_check( for datum in loader: assert isinstance(datum, Data) + # PPR sampling does not count per-hop neighbors, so num_sampled_edges + # should be absent or empty on all PPR output batches. + assert not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0, ( + f"Expected empty num_sampled_edges for PPR output, got {datum.num_sampled_edges}" + ) + assert hasattr(datum, "edge_index"), "Missing edge_index on Data" assert hasattr(datum, "edge_attr"), "Missing edge_attr on Data" @@ -372,14 +379,15 @@ def _run_ppr_loader_correctness_check( f" Reference: {sorted(reference_ppr.keys())}" ) - # Forward push is an approximation; with eps=1e-6 the per-node error - # is bounded by O(alpha * eps * degree). For this test graph - # (max degree 3, alpha=0.5, eps=1e-6) the theoretical bound is ~1.5e-6. - # Tolerance is set to 1e-5 to provide a safety margin above that bound. + # Forward push is an approximation; with eps=1e-6 the per-node + # requeue threshold is alpha * eps * degree. For this test graph + # (max degree 3, alpha=0.5, eps=1e-6) the per-node threshold is + # ~1.5e-6. Tolerance is set to 2e-6 to provide a small margin + # above this bound. for node_id in reference_ppr: ref_score = reference_ppr[node_id] sam_score = sampler_ppr[node_id] - assert abs(sam_score - ref_score) < 1e-5, ( + assert abs(sam_score - ref_score) < 2e-6, ( f"Seed {seed_global_id}, node {node_id}: " f"sampler={sam_score:.8f} vs reference={ref_score:.8f}" ) @@ -427,6 +435,12 @@ def _run_ppr_hetero_loader_correctness_check( for datum in loader: assert isinstance(datum, HeteroData) + # PPR sampling does not count per-hop neighbors, so num_sampled_edges + # should be absent or empty on all PPR output batches. + assert not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0, ( + f"Expected empty num_sampled_edges for PPR output, got {datum.num_sampled_edges}" + ) + seed_global_id = datum[USER].batch[0].item() ntype_to_sampler_ppr = _extract_hetero_ppr_scores( @@ -508,6 +522,12 @@ def _run_ppr_ablp_loader_correctness_check( for datum in loader: assert isinstance(datum, HeteroData) + # PPR sampling does not count per-hop neighbors, so num_sampled_edges + # should be absent or empty on all PPR output batches. + assert not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0, ( + f"Expected empty num_sampled_edges for PPR output, got {datum.num_sampled_edges}" + ) + # ABLP should produce positive labels alongside PPR metadata assert hasattr(datum, "y_positive"), "Missing y_positive on HeteroData" From 2197fa54624947d8ec38ce32fa0cb6283025c73c Mon Sep 17 00:00:00 2001 From: mkolodner Date: Fri, 1 May 2026 23:34:51 +0000 Subject: [PATCH 140/148] fmt --- gigl-core/core/sampling/ppr_forward_push.cpp | 75 ++++++++++++------- .../core/sampling/python_ppr_forward_push.cpp | 2 +- gigl/distributed/dist_ppr_sampler.py | 10 ++- .../unit/distributed/dist_ppr_sampler_test.py | 12 ++- 4 files changed, 65 insertions(+), 34 deletions(-) diff --git a/gigl-core/core/sampling/ppr_forward_push.cpp b/gigl-core/core/sampling/ppr_forward_push.cpp index 8abb1a25f..63669ebd8 100644 --- a/gigl-core/core/sampling/ppr_forward_push.cpp +++ b/gigl-core/core/sampling/ppr_forward_push.cpp @@ -15,8 +15,7 @@ namespace gigl { // Pack (node_id, etype_id) into a single uint64 for use as a hash key. // Inputs are cast through uint32_t to avoid sign-extension of negative int32 values. static uint64_t packKey(int32_t nodeId, int32_t edgeTypeId) { - return (static_cast(static_cast(nodeId)) << 32) | - static_cast(edgeTypeId); + return (static_cast(static_cast(nodeId)) << 32) | static_cast(edgeTypeId); } PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, @@ -39,26 +38,38 @@ PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, _batchSize = static_cast(seedNodes.size(0)); _numNodeTypes = static_cast(_nodeTypeToEdgeTypeIds.size()); - TORCH_CHECK(seedNodeTypeId >= 0, - "seedNodeTypeId ", seedNodeTypeId, " is negative."); - TORCH_CHECK(seedNodeTypeId < _numNodeTypes, - "seedNodeTypeId ", seedNodeTypeId, " out of range [0, ", _numNodeTypes, ")."); + TORCH_CHECK(seedNodeTypeId >= 0, "seedNodeTypeId ", seedNodeTypeId, " is negative."); + TORCH_CHECK( + seedNodeTypeId < _numNodeTypes, "seedNodeTypeId ", seedNodeTypeId, " out of range [0, ", _numNodeTypes, ")."); auto numEdgeTypes = static_cast(_edgeTypeToDstNtypeId.size()); for (int32_t edgeTypeId = 0; edgeTypeId < numEdgeTypes; ++edgeTypeId) { int32_t dstNodeTypeId = _edgeTypeToDstNtypeId[edgeTypeId]; - TORCH_CHECK(dstNodeTypeId >= 0, - "edgeTypeToDstNtypeId[", edgeTypeId, "] = ", dstNodeTypeId, " is negative."); + TORCH_CHECK(dstNodeTypeId >= 0, "edgeTypeToDstNtypeId[", edgeTypeId, "] = ", dstNodeTypeId, " is negative."); TORCH_CHECK(dstNodeTypeId < _numNodeTypes, - "edgeTypeToDstNtypeId[", edgeTypeId, "] = ", dstNodeTypeId, - " out of range [0, ", _numNodeTypes, ")."); + "edgeTypeToDstNtypeId[", + edgeTypeId, + "] = ", + dstNodeTypeId, + " out of range [0, ", + _numNodeTypes, + ")."); } for (int32_t nodeTypeId = 0; nodeTypeId < _numNodeTypes; ++nodeTypeId) { for (int32_t edgeTypeId : _nodeTypeToEdgeTypeIds[nodeTypeId]) { TORCH_CHECK(edgeTypeId >= 0, - "nodeTypeToEdgeTypeIds[", nodeTypeId, "] contains negative edge type id ", edgeTypeId, "."); + "nodeTypeToEdgeTypeIds[", + nodeTypeId, + "] contains negative edge type id ", + edgeTypeId, + "."); TORCH_CHECK(edgeTypeId < numEdgeTypes, - "nodeTypeToEdgeTypeIds[", nodeTypeId, "] contains edge type id ", edgeTypeId, - " out of range [0, ", numEdgeTypes, ")."); + "nodeTypeToEdgeTypeIds[", + nodeTypeId, + "] contains edge type id ", + edgeTypeId, + " out of range [0, ", + numEdgeTypes, + ")."); } } @@ -251,7 +262,8 @@ void PPRForwardPushState::pushResiduals( for (int32_t neighborNodeId : neighborList->get()) { dstNodeTypeState.residuals[neighborNodeId] += residualPerNeighbor; - double threshold = _requeueThresholdFactor * static_cast(getTotalDegree(neighborNodeId, dstNodeTypeId)); + double threshold = _requeueThresholdFactor * + static_cast(getTotalDegree(neighborNodeId, dstNodeTypeId)); if (dstNodeTypeState.queue.find(neighborNodeId) == dstNodeTypeState.queue.end() && dstNodeTypeState.residuals[neighborNodeId] >= threshold) { @@ -293,7 +305,9 @@ std::unordered_map(scores.size())); if (topK > 0) { std::vector> scorePairs(scores.begin(), scores.end()); - std::partial_sort(scorePairs.begin(), scorePairs.begin() + topK, scorePairs.end(), + std::partial_sort(scorePairs.begin(), + scorePairs.begin() + topK, + scorePairs.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); for (int32_t rankIdx = 0; rankIdx < topK; ++rankIdx) { @@ -312,30 +326,37 @@ std::unordered_map= 0, - "nodeTypeId ", nodeTypeId, " is negative, which indicates a sampler bug."); + TORCH_CHECK(nodeTypeId >= 0, "nodeTypeId ", nodeTypeId, " is negative, which indicates a sampler bug."); TORCH_CHECK(nodeTypeId < static_cast(_degreeTensors.size()), - "nodeTypeId ", nodeTypeId, " out of range [0, ", _degreeTensors.size(), + "nodeTypeId ", + nodeTypeId, + " out of range [0, ", + _degreeTensors.size(), "). This indicates a construction bug in the sampler."); const auto& degreeTensor = _degreeTensors[nodeTypeId]; if (degreeTensor.numel() == 0) { return 0; } - TORCH_CHECK(nodeId >= 0, - "Node ID ", nodeId, " is negative, which indicates a sampler bug."); + TORCH_CHECK(nodeId >= 0, "Node ID ", nodeId, " is negative, which indicates a sampler bug."); TORCH_CHECK(nodeId < static_cast(degreeTensor.size(0)), - "Node ID ", nodeId, " out of range for degree tensor of ntype_id ", - nodeTypeId, " (size=", degreeTensor.size(0), "). This indicates corrupted graph data or a sampler bug."); + "Node ID ", + nodeId, + " out of range for degree tensor of ntype_id ", + nodeTypeId, + " (size=", + degreeTensor.size(0), + "). This indicates corrupted graph data or a sampler bug."); if (degreeTensor.scalar_type() == torch::kInt) { return degreeTensor.data_ptr()[nodeId]; } if (degreeTensor.scalar_type() == torch::kLong) { - return static_cast( - std::min(degreeTensor.data_ptr()[nodeId], INT32_MAX)); + return static_cast(std::min(degreeTensor.data_ptr()[nodeId], INT32_MAX)); } - TORCH_CHECK(false, "Unsupported degree tensor dtype: ", degreeTensor.scalar_type(), + TORCH_CHECK(false, + "Unsupported degree tensor dtype: ", + degreeTensor.scalar_type(), ". Expected torch.int32 or torch.int64."); - return 0; // unreachable; suppresses compiler warning + return 0; // unreachable; suppresses compiler warning } -} // namespace gigl +} // namespace gigl diff --git a/gigl-core/core/sampling/python_ppr_forward_push.cpp b/gigl-core/core/sampling/python_ppr_forward_push.cpp index 300528afc..ae86387b0 100644 --- a/gigl-core/core/sampling/python_ppr_forward_push.cpp +++ b/gigl-core/core/sampling/python_ppr_forward_push.cpp @@ -39,7 +39,7 @@ static void pushResidualsWrapper(PPRForwardPushState& state, const py::dict& fet } } -} // namespace gigl +} // namespace gigl // TORCH_EXTENSION_NAME is set by PyTorch's build system to match the Python // module name derived from this file's path (e.g. "ppr_forward_push"). diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index e07e293c8..2f681e6db 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -3,6 +3,7 @@ from typing import Optional, Union import torch + # TODO: Once gigl_core has a stable Python interface, re-export PPRForwardPushState # under a gigl.core namespace rather than importing directly from the C++ extension. from gigl_core import PPRForwardPushState @@ -18,7 +19,6 @@ from gigl.distributed.base_sampler import BaseDistNeighborSampler from gigl.types.graph import is_label_edge_type - # Trailing "." is an intentional separator. These constants are used both to # write metadata keys (f"{KEY}{repr(edge_type)}" → e.g. "ppr_edge_index.('user', 'to', 'story')") # and as the strip prefix in extract_edge_type_metadata (key[len(prefix):] must @@ -163,7 +163,9 @@ def __init__( for etypes in self._node_type_to_edge_types.values() for et in etypes } - all_node_types: list[NodeType] = sorted(source_node_types | destination_node_types) + all_node_types: list[NodeType] = sorted( + source_node_types | destination_node_types + ) all_edge_types: list[EdgeType] = sorted( {et for etypes in self._node_type_to_edge_types.values() for et in etypes} ) @@ -613,7 +615,9 @@ async def _sample_from_nodes( edge_index = torch.stack([rows, cols]) else: edge_index = torch.zeros(2, 0, dtype=torch.long, device=self.device) - flat_weights = torch.zeros(0, dtype=torch.double, device=self.device) + flat_weights = torch.zeros( + 0, dtype=torch.double, device=self.device + ) etype_str = repr(ppr_edge_type) metadata[f"{PPR_EDGE_INDEX_METADATA_KEY}{etype_str}"] = edge_index metadata[f"{PPR_WEIGHT_METADATA_KEY}{etype_str}"] = flat_weights diff --git a/tests/unit/distributed/dist_ppr_sampler_test.py b/tests/unit/distributed/dist_ppr_sampler_test.py index 3e81f8d37..15369de72 100644 --- a/tests/unit/distributed/dist_ppr_sampler_test.py +++ b/tests/unit/distributed/dist_ppr_sampler_test.py @@ -332,7 +332,9 @@ def _run_ppr_loader_correctness_check( # PPR sampling does not count per-hop neighbors, so num_sampled_edges # should be absent or empty on all PPR output batches. - assert not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0, ( + assert ( + not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0 + ), ( f"Expected empty num_sampled_edges for PPR output, got {datum.num_sampled_edges}" ) @@ -437,7 +439,9 @@ def _run_ppr_hetero_loader_correctness_check( # PPR sampling does not count per-hop neighbors, so num_sampled_edges # should be absent or empty on all PPR output batches. - assert not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0, ( + assert ( + not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0 + ), ( f"Expected empty num_sampled_edges for PPR output, got {datum.num_sampled_edges}" ) @@ -524,7 +528,9 @@ def _run_ppr_ablp_loader_correctness_check( # PPR sampling does not count per-hop neighbors, so num_sampled_edges # should be absent or empty on all PPR output batches. - assert not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0, ( + assert ( + not hasattr(datum, "num_sampled_edges") or len(datum.num_sampled_edges) == 0 + ), ( f"Expected empty num_sampled_edges for PPR output, got {datum.num_sampled_edges}" ) From 2797c3a581b1c208c0934d763e6ea61f5885f121 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 4 May 2026 06:12:53 +0000 Subject: [PATCH 141/148] Cleanup + improve IDE with clangd --- gigl-core/.clangd | 5 +++ gigl-core/Makefile | 4 ++- gigl-core/core/sampling/ppr_forward_push.cpp | 11 +----- gigl-core/core/sampling/ppr_forward_push.h | 4 --- .../core/sampling/python_ppr_forward_push.cpp | 3 +- gigl-core/src/gigl_core/ppr_forward_push.pyi | 1 - gigl-core/tests/ppr_forward_push_test.cpp | 36 +++++++++++++------ 7 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 gigl-core/.clangd diff --git a/gigl-core/.clangd b/gigl-core/.clangd new file mode 100644 index 000000000..8a771fd30 --- /dev/null +++ b/gigl-core/.clangd @@ -0,0 +1,5 @@ +# Point clangd at the test compilation database rather than the default cmake_build one. +# The test database includes both the extension modules and the test binaries, so clangd +# can resolve gtest headers for test files alongside production headers. +CompileFlags: + CompilationDatabase: .cache/cpp_tests diff --git a/gigl-core/Makefile b/gigl-core/Makefile index 949db19ac..630aada59 100644 --- a/gigl-core/Makefile +++ b/gigl-core/Makefile @@ -15,7 +15,9 @@ CPP_SOURCES_NO_CUDA := $(filter-out %.cu,$(CPP_SOURCES)) .cache/cmake_build/CMakeInit.txt: $(shell find core \( -name '*.cpp' -o -name '*.cu' -o -name '*.h' -o -name '*.cuh' \) 2>/dev/null) CMakeLists.txt pyproject.toml cd $(abspath $(CURDIR)/..) && uv pip install -e gigl-core/ -build_cpp_extensions: .cache/cmake_build/CMakeInit.txt +# Also depend on the test cmake configure so that .cache/cpp_tests/compile_commands.json +# is generated automatically, giving clangd visibility into test files and gtest headers. +build_cpp_extensions: .cache/cmake_build/CMakeInit.txt .cache/cpp_tests/.configured .cache/cpp_tests/.configured: CMakeLists.txt tests/CMakeLists.txt .cache/cmake_build/CMakeInit.txt cmake -C .cache/cmake_build/CMakeInit.txt -S . -B .cache/cpp_tests -DGIGL_CORE_BUILD_TESTS=ON diff --git a/gigl-core/core/sampling/ppr_forward_push.cpp b/gigl-core/core/sampling/ppr_forward_push.cpp index 63669ebd8..6741ae3ec 100644 --- a/gigl-core/core/sampling/ppr_forward_push.cpp +++ b/gigl-core/core/sampling/ppr_forward_push.cpp @@ -110,7 +110,6 @@ std::optional> PPRForwardPushState::d // in multiple seeds' queues: we only fetch each (node, etype) pair once. std::unordered_map> nodesToLookup; - int32_t totalDrainedThisRound = 0; for (int32_t seedIdx = 0; seedIdx < _batchSize; ++seedIdx) { for (int32_t nodeTypeId = 0; nodeTypeId < _numNodeTypes; ++nodeTypeId) { auto& seedNodeTypeState = _state[seedIdx][nodeTypeId]; @@ -123,9 +122,7 @@ std::optional> PPRForwardPushState::d // a moved-from container is "valid but unspecified", not necessarily empty. seedNodeTypeState.queuedNodes = std::move(seedNodeTypeState.queue); seedNodeTypeState.queue.clear(); - auto numDrained = static_cast(seedNodeTypeState.queuedNodes.size()); - totalDrainedThisRound += numDrained; - _numNodesInQueue -= numDrained; + _numNodesInQueue -= static_cast(seedNodeTypeState.queuedNodes.size()); for (int32_t nodeId : seedNodeTypeState.queuedNodes) { for (int32_t edgeTypeId : _nodeTypeToEdgeTypeIds[nodeTypeId]) { @@ -137,8 +134,6 @@ std::optional> PPRForwardPushState::d } } - _nodesDrainedPerIteration.push_back(totalDrainedThisRound); - std::unordered_map result; for (const auto& [edgeTypeId, nodeSet] : nodesToLookup) { std::vector nodeIdsToLookup(nodeSet.begin(), nodeSet.end()); @@ -147,10 +142,6 @@ std::optional> PPRForwardPushState::d return result; } -const std::vector& PPRForwardPushState::getNodesDrainedPerIteration() const { - return _nodesDrainedPerIteration; -} - void PPRForwardPushState::pushResiduals( const std::unordered_map>& fetchedByEtypeId) { // Step 1: Unpack the input map into a C++ map keyed by packKey(nodeId, edgeTypeId) diff --git a/gigl-core/core/sampling/ppr_forward_push.h b/gigl-core/core/sampling/ppr_forward_push.h index 694f37c59..d0e6b16a4 100644 --- a/gigl-core/core/sampling/ppr_forward_push.h +++ b/gigl-core/core/sampling/ppr_forward_push.h @@ -61,8 +61,6 @@ class PPRForwardPushState { std::unordered_map> extractTopK(int32_t maxPprNodes); - // Total nodes drained per drainQueue() call, across all seeds and node types. - [[nodiscard]] const std::vector& getNodesDrainedPerIteration() const; private: // Total out-degree of a node across all edge types. Returns 0 for sink nodes. @@ -100,8 +98,6 @@ class PPRForwardPushState { // Populated incrementally as nodes are processed; avoids re-fetching the same node twice. std::unordered_map> _neighborCache; - // Total nodes drained (across all seeds and types) per drainQueue() call. - std::vector _nodesDrainedPerIteration; }; } // namespace gigl diff --git a/gigl-core/core/sampling/python_ppr_forward_push.cpp b/gigl-core/core/sampling/python_ppr_forward_push.cpp index ae86387b0..009fd0bd3 100644 --- a/gigl-core/core/sampling/python_ppr_forward_push.cpp +++ b/gigl-core/core/sampling/python_ppr_forward_push.cpp @@ -54,6 +54,5 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { std::vector>()) .def("drain_queue", &gigl::PPRForwardPushState::drainQueue) .def("push_residuals", gigl::pushResidualsWrapper) - .def("extract_top_k", &gigl::PPRForwardPushState::extractTopK) - .def("get_nodes_drained_per_iteration", &gigl::PPRForwardPushState::getNodesDrainedPerIteration); + .def("extract_top_k", &gigl::PPRForwardPushState::extractTopK); } diff --git a/gigl-core/src/gigl_core/ppr_forward_push.pyi b/gigl-core/src/gigl_core/ppr_forward_push.pyi index 9a3c78fea..265468c3c 100644 --- a/gigl-core/src/gigl_core/ppr_forward_push.pyi +++ b/gigl-core/src/gigl_core/ppr_forward_push.pyi @@ -19,4 +19,3 @@ class PPRForwardPushState: def extract_top_k( self, max_ppr_nodes: int ) -> dict[int, tuple[torch.Tensor, torch.Tensor, torch.Tensor]]: ... - def get_nodes_drained_per_iteration(self) -> list[int]: ... diff --git a/gigl-core/tests/ppr_forward_push_test.cpp b/gigl-core/tests/ppr_forward_push_test.cpp index 22e461b40..44e932a3b 100644 --- a/gigl-core/tests/ppr_forward_push_test.cpp +++ b/gigl-core/tests/ppr_forward_push_test.cpp @@ -22,13 +22,13 @@ static PPRForwardPushState makeState( // Convenience wrapper: build the fetchedByEtypeId argument for pushResiduals // from flat vectors, keeping test call sites readable. static std::unordered_map> -makeFetched(int32_t etypeId, +makeFetched(int32_t edgeTypeId, std::vector nodeIds, - std::vector flatNbrs, + std::vector flatNeighborIds, std::vector counts) { - return {{etypeId, + return {{edgeTypeId, {torch::tensor(nodeIds, torch::kLong), - torch::tensor(flatNbrs, torch::kLong), + torch::tensor(flatNeighborIds, torch::kLong), torch::tensor(counts, torch::kLong)}}}; } @@ -70,7 +70,7 @@ TEST(PPRForwardPush, ResidualDistributedToNeighbor) { // Iteration 1: seed node 0 → neighbor node 1. state.drainQueue(); - state.pushResiduals(makeFetched(/*etypeId=*/0, /*nodeIds=*/{0}, /*flatNbrs=*/{1}, /*counts=*/{1})); + state.pushResiduals(makeFetched(/*edgeTypeId=*/0, /*nodeIds=*/{0}, /*flatNeighborIds=*/{1}, /*counts=*/{1})); // Iteration 2: node 1 is a sink; absorbs its residual, no further push. state.drainQueue(); @@ -88,19 +88,33 @@ TEST(PPRForwardPush, ResidualDistributedToNeighbor) { EXPECT_NEAR(weights[1].item(), static_cast((1.0 - alpha) * alpha), 1e-5f); } -// Two seeds both push residual to node 2; the neighbor-lookup request deduplicates -// to one entry, but getNodesDrainedPerIteration counts both seed queues. +// Two seeds (0 and 1) both push residual to sink node 2. The neighbor-lookup +// request must deduplicate to one entry for node 2, yet both seeds must still +// accumulate a PPR score for it. TEST(PPRForwardPush, DeduplicatesNodesAcrossSeeds) { auto state = makeState(/*seeds=*/{0, 1}, /*alpha=*/0.15, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{1, 1, 0}); state.drainQueue(); - state.pushResiduals(makeFetched(/*etypeId=*/0, /*nodeIds=*/{0, 1}, /*flatNbrs=*/{2, 2}, /*counts=*/{1, 1})); + state.pushResiduals(makeFetched(/*edgeTypeId=*/0, /*nodeIds=*/{0, 1}, /*flatNeighborIds=*/{2, 2}, /*counts=*/{1, 1})); auto iter2 = state.drainQueue(); ASSERT_TRUE(iter2.has_value()); ASSERT_NE(iter2->find(0), iter2->end()); - EXPECT_EQ(iter2->at(0).size(0), 1); // node 2 deduplicated in lookup - EXPECT_EQ(state.getNodesDrainedPerIteration()[1], 2); // but drained from 2 seed queues + EXPECT_EQ(iter2->at(0).size(0), 1); // node 2 deduplicated in the lookup request + + state.pushResiduals({}); + EXPECT_FALSE(state.drainQueue().has_value()); + + auto topk = state.extractTopK(10); + ASSERT_NE(topk.find(0), topk.end()); + const auto& [ids, weights, counts] = topk.at(0); + // Each seed (batch indices 0 and 1) should have 2 nodes in its top-k. + EXPECT_EQ(counts[0].item(), 2); // seed 0: nodes {0, 2} + EXPECT_EQ(counts[1].item(), 2); // seed 1: nodes {1, 2} + // The flat id layout is [seed0_top1, seed0_top2, seed1_top1, seed1_top2]. + // Within each seed the highest scorer comes first, so seed-node beats node 2. + EXPECT_EQ(ids[1].item(), 2); // seed 0's second node is node 2 + EXPECT_EQ(ids[3].item(), 2); // seed 1's second node is node 2 } // extractTopK respects the maxPprNodes limit. @@ -108,7 +122,7 @@ TEST(PPRForwardPush, ExtractTopKLimitsResults) { auto state = makeState(/*seeds=*/{0}, /*alpha=*/0.15, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{1, 0}); state.drainQueue(); - state.pushResiduals(makeFetched(/*etypeId=*/0, /*nodeIds=*/{0}, /*flatNbrs=*/{1}, /*counts=*/{1})); + state.pushResiduals(makeFetched(/*edgeTypeId=*/0, /*nodeIds=*/{0}, /*flatNeighborIds=*/{1}, /*counts=*/{1})); state.drainQueue(); state.pushResiduals({}); From ee188ac30cd79dd568da69021a1653625311d9f1 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 4 May 2026 06:37:12 +0000 Subject: [PATCH 142/148] Additional cleanup --- gigl-core/core/sampling/ppr_forward_push.cpp | 4 ++++ gigl-core/core/sampling/ppr_forward_push.h | 1 - gigl/distributed/dist_ppr_sampler.py | 6 ------ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/gigl-core/core/sampling/ppr_forward_push.cpp b/gigl-core/core/sampling/ppr_forward_push.cpp index 6741ae3ec..3cc60651d 100644 --- a/gigl-core/core/sampling/ppr_forward_push.cpp +++ b/gigl-core/core/sampling/ppr_forward_push.cpp @@ -110,6 +110,10 @@ std::optional> PPRForwardPushState::d // in multiple seeds' queues: we only fetch each (node, etype) pair once. std::unordered_map> nodesToLookup; + // TODO: For homogeneous graphs _numNodeTypes == 1, so the inner loop always + // executes exactly once (nodeTypeId=0). std::vector indexing is cheap, but a + // dedicated homogeneous code path could eliminate the loop entirely. Profile + // before splitting. for (int32_t seedIdx = 0; seedIdx < _batchSize; ++seedIdx) { for (int32_t nodeTypeId = 0; nodeTypeId < _numNodeTypes; ++nodeTypeId) { auto& seedNodeTypeState = _state[seedIdx][nodeTypeId]; diff --git a/gigl-core/core/sampling/ppr_forward_push.h b/gigl-core/core/sampling/ppr_forward_push.h index d0e6b16a4..7d95ba144 100644 --- a/gigl-core/core/sampling/ppr_forward_push.h +++ b/gigl-core/core/sampling/ppr_forward_push.h @@ -61,7 +61,6 @@ class PPRForwardPushState { std::unordered_map> extractTopK(int32_t maxPprNodes); - private: // Total out-degree of a node across all edge types. Returns 0 for sink nodes. [[nodiscard]] int32_t getTotalDegree(int32_t nodeId, int32_t nodeTypeId) const; diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index 2f681e6db..c282be2d4 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -29,11 +29,6 @@ # Sentinel type names for homogeneous graphs. The PPR algorithm uses # dict[NodeType, ...] internally for both homo and hetero graphs; these # sentinels let the homogeneous path reuse the same dict-based code. -# TODO (mkolodner-sc): The sentinel approach adds an extra dict lookup on -# every operation in the hot loop for homogeneous graphs (always resolving -# the same single key). Profile whether this overhead is meaningful -# compared to the neighbor fetch and residual update costs, and consider -# splitting into separate homo/hetero loop implementations if so. _PPR_HOMOGENEOUS_NODE_TYPE = "ppr_homogeneous_node_type" _PPR_HOMOGENEOUS_EDGE_TYPE = ( _PPR_HOMOGENEOUS_NODE_TYPE, @@ -99,7 +94,6 @@ def __init__( ): super().__init__(*args, **kwargs) self._alpha = alpha - self._eps = eps self._max_ppr_nodes = max_ppr_nodes self._requeue_threshold_factor = alpha * eps self._num_neighbors_per_hop = num_neighbors_per_hop From 419bab0b43d6f89fd8b7e55de3a9d10474dcb349 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 4 May 2026 18:25:48 +0000 Subject: [PATCH 143/148] Last comments --- Makefile | 19 +++------- gigl-core/Makefile | 17 ++++++++- gigl-core/core/sampling/ppr_forward_push.cpp | 31 ++++++++-------- gigl-core/core/sampling/ppr_forward_push.h | 30 +++++++++------- .../core/sampling/python_ppr_forward_push.cpp | 13 ++++--- .../scripts}/run_cpp_lint.py | 8 ++--- gigl-core/src/gigl_core/__init__.py | 4 +-- gigl-core/src/gigl_core/ppr_forward_push.pyi | 2 +- gigl-core/tests/ppr_forward_push_test.cpp | 36 ++++++++++--------- gigl/distributed/dist_ppr_sampler.py | 10 +++--- 10 files changed, 94 insertions(+), 76 deletions(-) rename {scripts => gigl-core/scripts}/run_cpp_lint.py (92%) diff --git a/Makefile b/Makefile index 06752d5af..359664ea7 100644 --- a/Makefile +++ b/Makefile @@ -165,20 +165,11 @@ type_check: build_cpp_extensions: $(MAKE) -C gigl-core build_cpp_extensions -check_lint_cpp: build_cpp_extensions - uv run python -m scripts.run_cpp_lint $(CPP_SOURCES_NO_CUDA) - -# Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, -# changes expressions, adds/removes keywords), not just style. Run manually and -# review the diff before committing. Note: --fix cannot auto-repair every check; -# some violations require manual edits. -# --extra-arg=-Wno-ignored-optimization-argument suppresses GCC-specific LTO flags -# (-fno-fat-lto-objects, -flto=auto) that cmake writes into compile_commands.json. -# clang-tidy forwards compiler warnings via clang-diagnostic-*, and .clang-tidy sets -# WarningsAsErrors: '*', so the warning must be silenced at the compiler level before -# clang-tidy ever sees it. -fix_lint_cpp: build_cpp_extensions - clang-tidy-15 --fix --extra-arg=-Wno-ignored-optimization-argument -p gigl-core/.cache/cmake_build/compile_commands.json $(CPP_SOURCES_NO_CUDA) +check_lint_cpp: + $(MAKE) -C gigl-core check_lint_cpp + +fix_lint_cpp: + $(MAKE) -C gigl-core fix_lint_cpp lint_test: check_format assert_yaml_configs_parse check_lint_cpp @echo "Lint checks pass!" diff --git a/gigl-core/Makefile b/gigl-core/Makefile index 630aada59..85b5fab68 100644 --- a/gigl-core/Makefile +++ b/gigl-core/Makefile @@ -33,6 +33,21 @@ check_format_cpp: format_cpp: clang-format-15 -i --style=file $(CPP_SOURCES) +# Not part of `make format`: clang-tidy --fix rewrites logic (renames identifiers, +# changes expressions, adds/removes keywords), not just style. Run manually and +# review the diff before committing. Note: --fix cannot auto-repair every check; +# some violations require manual edits. +# --extra-arg=-Wno-ignored-optimization-argument suppresses GCC-specific LTO flags +# (-fno-fat-lto-objects, -flto=auto) that cmake writes into compile_commands.json. +# clang-tidy forwards compiler warnings via clang-diagnostic-*, and .clang-tidy sets +# WarningsAsErrors: '*', so the warning must be silenced at the compiler level before +# clang-tidy ever sees it. +check_lint_cpp: build_cpp_extensions + uv run python scripts/run_cpp_lint.py $(CPP_SOURCES_NO_CUDA) + +fix_lint_cpp: build_cpp_extensions + clang-tidy-15 --fix --extra-arg=-Wno-ignored-optimization-argument -p .cache/cmake_build/compile_commands.json $(CPP_SOURCES_NO_CUDA) + # Wipe cmake build caches. Use this if cmake's cached state becomes inconsistent # after switching between branches with substantially different CMakeLists.txt structure. clean_cpp: @@ -43,4 +58,4 @@ clean_build_files_cpp: # Declare targets as phony so make always runs their recipes, even if a file or # directory with the same name happens to exist on disk. -.PHONY: build_cpp_extensions unit_test_cpp check_format_cpp format_cpp clean_cpp clean_build_files_cpp +.PHONY: build_cpp_extensions unit_test_cpp check_format_cpp format_cpp check_lint_cpp fix_lint_cpp clean_cpp clean_build_files_cpp diff --git a/gigl-core/core/sampling/ppr_forward_push.cpp b/gigl-core/core/sampling/ppr_forward_push.cpp index 3cc60651d..9a2a17f03 100644 --- a/gigl-core/core/sampling/ppr_forward_push.cpp +++ b/gigl-core/core/sampling/ppr_forward_push.cpp @@ -18,13 +18,13 @@ static uint64_t packKey(int32_t nodeId, int32_t edgeTypeId) { return (static_cast(static_cast(nodeId)) << 32) | static_cast(edgeTypeId); } -PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, - int32_t seedNodeTypeId, - double alpha, - double requeueThresholdFactor, - std::vector> nodeTypeToEdgeTypeIds, - std::vector edgeTypeToDstNtypeId, - std::vector degreeTensors) +PPRForwardPush::PPRForwardPush(const torch::Tensor& seedNodes, + int32_t seedNodeTypeId, + double alpha, + double requeueThresholdFactor, + std::vector> nodeTypeToEdgeTypeIds, + std::vector edgeTypeToDstNtypeId, + std::vector degreeTensors) : _alpha(alpha), _requeueThresholdFactor(requeueThresholdFactor), // std::move transfers ownership of each vector into the member variable @@ -91,7 +91,7 @@ PPRForwardPushState::PPRForwardPushState(const torch::Tensor& seedNodes, } } -std::optional> PPRForwardPushState::drainQueue() { +std::optional> PPRForwardPush::drainQueue() { if (_numNodesInQueue == 0) { return std::nullopt; } @@ -146,7 +146,7 @@ std::optional> PPRForwardPushState::d return result; } -void PPRForwardPushState::pushResiduals( +void PPRForwardPush::pushResiduals( const std::unordered_map>& fetchedByEtypeId) { // Step 1: Unpack the input map into a C++ map keyed by packKey(nodeId, edgeTypeId) // for fast lookup during the residual-push loop below. @@ -232,9 +232,12 @@ void PPRForwardPushState::pushResiduals( // any given (node, etype) key within one iteration. drainQueue() // only requests a fetch for nodes absent from _neighborCache, so a // key is in at most one of the two. - // Neighbor list for this (src, edgeTypeId) pair, if one exists — - // either from `fetched` (new this iteration) or `_neighborCache` - // (seen in a previous iteration). + // + // Neighbor list for this (src, edgeTypeId) pair, borrowed from whichever + // map holds it. reference_wrapper is used because std::optional cannot + // hold a reference directly, and we want to avoid copying the vector — + // the data already exists in fetched or _neighborCache and both outlive + // this loop body. Access via neighborList->get(). std::optional>> neighborList; auto fetchedEntry = fetched.find(packKey(sourceNodeId, edgeTypeId)); if (fetchedEntry != fetched.end()) { @@ -284,7 +287,7 @@ void PPRForwardPushState::pushResiduals( } } -std::unordered_map> PPRForwardPushState::extractTopK( +std::unordered_map> PPRForwardPush::extractTopK( int32_t maxPprNodes) { std::unordered_map> result; // Emit an entry for every node type, even if unreachable in this batch (empty tensors, @@ -320,7 +323,7 @@ std::unordered_map= 0, "nodeTypeId ", nodeTypeId, " is negative, which indicates a sampler bug."); TORCH_CHECK(nodeTypeId < static_cast(_degreeTensors.size()), "nodeTypeId ", diff --git a/gigl-core/core/sampling/ppr_forward_push.h b/gigl-core/core/sampling/ppr_forward_push.h index 7d95ba144..1c1eef670 100644 --- a/gigl-core/core/sampling/ppr_forward_push.h +++ b/gigl-core/core/sampling/ppr_forward_push.h @@ -13,10 +13,12 @@ namespace gigl { // Per-seed, per-node-type PPR algorithm state. -// Grouping all four tables into one struct keeps related data co-located in memory: -// when the push loop accesses pprScores, residuals, queue, and queuedNodes for the -// same (seed, ntype) pair, they are in the same cache line region rather than spread -// across four separate top-level vectors. +// Grouping all four tables into one struct is a logical convenience: a single +// _state[seedIdx][nodeTypeId] access reaches all four tables for a given (seed, ntype) +// pair, rather than indexing four separate 2D arrays. Note that unordered_map and +// unordered_set heap-allocate their bucket storage, so the actual key-value data is +// not co-located in memory — only the control-plane metadata (size, bucket pointer) +// lives inside the struct. struct SeedNodeTypeState { std::unordered_map pprScores; // absorbed PPR mass std::unordered_map residuals; // unabsorbed mass waiting to push @@ -28,15 +30,15 @@ struct SeedNodeTypeState { // Hot-loop state lives here; distributed neighbor fetches are driven from Python. // // Call sequence per batch: -// 1. PPRForwardPushState(seedNodes, ...) +// 1. PPRForwardPush(seedNodes, ...) // while True: // 2. drainQueue() → nodes needing neighbor lookup // 3. // 4. pushResiduals(fetchedByEtypeId) // 5. extractTopK(maxPprNodes) -class PPRForwardPushState { +class PPRForwardPush { public: - PPRForwardPushState(const torch::Tensor& seedNodes, + PPRForwardPush(const torch::Tensor& seedNodes, int32_t seedNodeTypeId, double alpha, double requeueThresholdFactor, @@ -68,6 +70,10 @@ class PPRForwardPushState { double _alpha; double _requeueThresholdFactor; // alpha * eps; per-node requeue threshold = factor * degree + // NOTE: int32_t is used for batch size, node IDs, and type IDs throughout this class. + // All of this code will break silently (overflow) if batch size or node IDs exceed ~2B + // (INT32_MAX = 2,147,483,647). This is not a realistic concern today, but if graph + // scale ever approaches that threshold, these should be widened to int64_t. int32_t _batchSize; // number of seed nodes in the current batch int32_t _numNodeTypes; // total distinct node types (1 for homogeneous graphs) int32_t _numNodesInQueue{0}; // running count of queued nodes across all seeds and types @@ -81,9 +87,8 @@ class PPRForwardPushState { std::vector _degreeTensors; // Per-seed, per-node-type PPR state. Indexed as _state[seedIdx][nodeTypeId]. - // - // outer vector [_batchSize] — one entry per seed node in the batch - // inner vector [_numNodeTypes] — one SeedNodeTypeState per node type + // 2D vector: both dimensions are dense sequential integers bounded at construction, + // so array indexing is O(1) with no hashing (contrast with _neighborCache below). // // int32_t is used for node and type IDs throughout to match PyG/GLT's signed-integer // convention (torch.int32 / torch.int64). Signed types also make nodeId >= 0 checks @@ -93,8 +98,9 @@ class PPRForwardPushState { // so [seedIdx][nodeTypeId] indexing is always safe within the loop bounds. std::vector> _state; - // Neighbor lists fetched from the distributed graph store, keyed by packKey(node_id, etype_id). - // Populated incrementally as nodes are processed; avoids re-fetching the same node twice. + // Neighbor lists keyed by packKey(nodeId, edgeTypeId). + // Hash map: nodeId is a sparse graph ID from a large graph, so a dense array is + // impractical (contrast with _state above). Populated incrementally; avoids re-fetching. std::unordered_map> _neighborCache; }; diff --git a/gigl-core/core/sampling/python_ppr_forward_push.cpp b/gigl-core/core/sampling/python_ppr_forward_push.cpp index 009fd0bd3..22981a48a 100644 --- a/gigl-core/core/sampling/python_ppr_forward_push.cpp +++ b/gigl-core/core/sampling/python_ppr_forward_push.cpp @@ -1,4 +1,4 @@ -// Python bindings for PPRForwardPushState. +// Python bindings for PPRForwardPush. // // Pure C++ algorithm lives in ppr_forward_push.{h,cpp}; this file only handles // type conversion between Python (pybind11) and C++ types, then delegates to @@ -20,7 +20,7 @@ namespace gigl { // pushResiduals: a wrapper is needed solely to release the GIL during the C++ push. // pybind11/stl.h handles all type conversions automatically; the other methods use // direct member function pointers for the same reason. -static void pushResidualsWrapper(PPRForwardPushState& state, const py::dict& fetchedByEtypeId) { +static void pushResidualsWrapper(PPRForwardPush& state, const py::dict& fetchedByEtypeId) { std::unordered_map> neighborTensorsByEtypeId; // Dict iteration touches Python objects — GIL must be held here. for (auto item : fetchedByEtypeId) { @@ -33,6 +33,9 @@ static void pushResidualsWrapper(PPRForwardPushState& state, const py::dict& fet // C++ push only uses tensor accessor/data_ptr APIs — GIL-safe to release. // Releasing here lets the asyncio event loop process RPC completion callbacks // from other concurrent PPR coroutines while this push runs. + // REQUIREMENT: no other thread may read or modify neighborTensorsByEtypeId or + // the underlying tensor data while the GIL is released. The caller (Python) + // must not alias or mutate fetchedByEtypeId until push_residuals returns. { py::gil_scoped_release release; state.pushResiduals(neighborTensorsByEtypeId); @@ -44,7 +47,7 @@ static void pushResidualsWrapper(PPRForwardPushState& state, const py::dict& fet // TORCH_EXTENSION_NAME is set by PyTorch's build system to match the Python // module name derived from this file's path (e.g. "ppr_forward_push"). PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - py::class_(m, "PPRForwardPushState") + py::class_(m, "PPRForwardPush") .def(py::init>, std::vector, std::vector>()) - .def("drain_queue", &gigl::PPRForwardPushState::drainQueue) + .def("drain_queue", &gigl::PPRForwardPush::drainQueue) .def("push_residuals", gigl::pushResidualsWrapper) - .def("extract_top_k", &gigl::PPRForwardPushState::extractTopK); + .def("extract_top_k", &gigl::PPRForwardPush::extractTopK); } diff --git a/scripts/run_cpp_lint.py b/gigl-core/scripts/run_cpp_lint.py similarity index 92% rename from scripts/run_cpp_lint.py rename to gigl-core/scripts/run_cpp_lint.py index 7e2db01c9..32cebd9e2 100644 --- a/scripts/run_cpp_lint.py +++ b/gigl-core/scripts/run_cpp_lint.py @@ -2,7 +2,7 @@ Runs clangd --check on each file in parallel and prints a clean summary. Expects compile_commands.json to already exist at -gigl-core/.cache/cmake_build/compile_commands.json; call +.cache/cmake_build/compile_commands.json; call ``make build_cpp_extensions`` first if it is absent or stale (``make check_lint_cpp`` does this automatically via a Makefile prerequisite). @@ -17,10 +17,8 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path -_REPO_ROOT = Path(__file__).resolve().parent.parent -COMPILE_COMMANDS = ( - _REPO_ROOT / "gigl-core" / ".cache" / "cmake_build" / "compile_commands.json" -) +_GIGL_CORE_ROOT = Path(__file__).resolve().parent.parent +COMPILE_COMMANDS = _GIGL_CORE_ROOT / ".cache" / "cmake_build" / "compile_commands.json" # Matches real clang-tidy diagnostics emitted by clangd: # E[HH:MM:SS.mmm] [check-name] Line N: message diff --git a/gigl-core/src/gigl_core/__init__.py b/gigl-core/src/gigl_core/__init__.py index 7c23be783..524135619 100644 --- a/gigl-core/src/gigl_core/__init__.py +++ b/gigl-core/src/gigl_core/__init__.py @@ -1,3 +1,3 @@ -from gigl_core.ppr_forward_push import PPRForwardPushState +from gigl_core.ppr_forward_push import PPRForwardPush -__all__ = ["PPRForwardPushState"] +__all__ = ["PPRForwardPush"] diff --git a/gigl-core/src/gigl_core/ppr_forward_push.pyi b/gigl-core/src/gigl_core/ppr_forward_push.pyi index 265468c3c..0c1ea79af 100644 --- a/gigl-core/src/gigl_core/ppr_forward_push.pyi +++ b/gigl-core/src/gigl_core/ppr_forward_push.pyi @@ -1,6 +1,6 @@ import torch -class PPRForwardPushState: +class PPRForwardPush: def __init__( self, seed_nodes: torch.Tensor, diff --git a/gigl-core/tests/ppr_forward_push_test.cpp b/gigl-core/tests/ppr_forward_push_test.cpp index 44e932a3b..604763deb 100644 --- a/gigl-core/tests/ppr_forward_push_test.cpp +++ b/gigl-core/tests/ppr_forward_push_test.cpp @@ -1,15 +1,15 @@ #include #include "sampling/ppr_forward_push.h" -using gigl::PPRForwardPushState; +using gigl::PPRForwardPush; -// Builds a single-edge-type, single-node-type PPRForwardPushState. -static PPRForwardPushState makeState( - std::vector seeds, +// Builds a single-edge-type, single-node-type PPRForwardPush. +static PPRForwardPush makeState( + const std::vector& seeds, double alpha, double requeueThresholdFactor, - std::vector degrees) { - return PPRForwardPushState( + const std::vector& degrees) { + return PPRForwardPush( torch::tensor(seeds, torch::kLong), /*seedNodeTypeId=*/0, alpha, @@ -23,9 +23,9 @@ static PPRForwardPushState makeState( // from flat vectors, keeping test call sites readable. static std::unordered_map> makeFetched(int32_t edgeTypeId, - std::vector nodeIds, - std::vector flatNeighborIds, - std::vector counts) { + const std::vector& nodeIds, + const std::vector& flatNeighborIds, + const std::vector& counts) { return {{edgeTypeId, {torch::tensor(nodeIds, torch::kLong), torch::tensor(flatNeighborIds, torch::kLong), @@ -37,9 +37,10 @@ TEST(PPRForwardPush, DrainQueueReturnsSeedNodeInitially) { auto state = makeState(/*seeds=*/{0}, /*alpha=*/0.15, /*requeueThresholdFactor=*/1e-6, /*degrees=*/{1}); auto result = state.drainQueue(); ASSERT_TRUE(result.has_value()); - ASSERT_NE(result->find(0), result->end()); - EXPECT_EQ(result->at(0).size(0), 1); - EXPECT_EQ(result->at(0)[0].item(), 0); + const auto& nodeMap = result.value(); + ASSERT_NE(nodeMap.find(0), nodeMap.end()); + EXPECT_EQ(nodeMap.at(0).size(0), 1); + EXPECT_EQ(nodeMap.at(0)[0].item(), 0); } // After convergence (sink node absorbs all residual), drainQueue() returns nullopt. @@ -60,7 +61,7 @@ TEST(PPRForwardPush, PprScoreAbsorbsAlpha) { ASSERT_NE(topk.find(0), topk.end()); const auto& [ids, weights, counts] = topk.at(0); EXPECT_EQ(ids[0].item(), 0); - EXPECT_NEAR(weights[0].item(), static_cast(alpha), 1e-5f); + EXPECT_NEAR(weights[0].item(), static_cast(alpha), 1e-5F); } // Node 0 (degree 1) pushes (1-alpha)*alpha residual to node 1 (sink). @@ -84,8 +85,8 @@ TEST(PPRForwardPush, ResidualDistributedToNeighbor) { ASSERT_EQ(counts[0].item(), 2); EXPECT_EQ(ids[0].item(), 0); EXPECT_EQ(ids[1].item(), 1); - EXPECT_NEAR(weights[0].item(), static_cast(alpha), 1e-5f); - EXPECT_NEAR(weights[1].item(), static_cast((1.0 - alpha) * alpha), 1e-5f); + EXPECT_NEAR(weights[0].item(), static_cast(alpha), 1e-5F); + EXPECT_NEAR(weights[1].item(), static_cast((1.0 - alpha) * alpha), 1e-5F); } // Two seeds (0 and 1) both push residual to sink node 2. The neighbor-lookup @@ -99,8 +100,9 @@ TEST(PPRForwardPush, DeduplicatesNodesAcrossSeeds) { auto iter2 = state.drainQueue(); ASSERT_TRUE(iter2.has_value()); - ASSERT_NE(iter2->find(0), iter2->end()); - EXPECT_EQ(iter2->at(0).size(0), 1); // node 2 deduplicated in the lookup request + const auto& iter2Map = iter2.value(); + ASSERT_NE(iter2Map.find(0), iter2Map.end()); + EXPECT_EQ(iter2Map.at(0).size(0), 1); // node 2 deduplicated in the lookup request state.pushResiduals({}); EXPECT_FALSE(state.drainQueue().has_value()); diff --git a/gigl/distributed/dist_ppr_sampler.py b/gigl/distributed/dist_ppr_sampler.py index c282be2d4..83369d8c2 100644 --- a/gigl/distributed/dist_ppr_sampler.py +++ b/gigl/distributed/dist_ppr_sampler.py @@ -4,9 +4,9 @@ import torch -# TODO: Once gigl_core has a stable Python interface, re-export PPRForwardPushState +# TODO: Once gigl_core has a stable Python interface, re-export PPRForwardPush # under a gigl.core namespace rather than importing directly from the C++ extension. -from gigl_core import PPRForwardPushState +from gigl_core import PPRForwardPush from graphlearn_torch.sampler import ( HeteroSamplerOutput, NeighborOutput, @@ -146,7 +146,7 @@ def __init__( # Build integer ID mappings for the C++ forward-push kernel. String # NodeType / EdgeType keys are only used at the Python boundary # (translating to/from _sample_one_hop); all hot-loop state inside - # PPRForwardPushState is indexed by int32 IDs. + # PPRForwardPush is indexed by int32 IDs. # # We include both source types (have outgoing edges) and destination-only # types (no outgoing edges, but may accumulate PPR score during the walk) @@ -365,7 +365,7 @@ async def _compute_ppr_scores( seed_node_type = _PPR_HOMOGENEOUS_NODE_TYPE device = seed_nodes.device - ppr_state = PPRForwardPushState( + ppr_state = PPRForwardPush( seed_nodes, self._node_type_to_id[seed_node_type], self._alpha, @@ -529,7 +529,7 @@ async def _sample_from_nodes( # arbitrary. # # Each seed type's PPR computation is entirely independent: it creates - # its own PPRForwardPushState and only reads shared sampler attributes + # its own PPRForwardPush and only reads shared sampler attributes # (degree tensors, edge-type maps) which are immutable after __init__. # Running them with asyncio.gather allows their fetch phases to overlap, # which is most beneficial when there are 2+ distinct seed node types From b00151cb9c8c9a3fce3734bfc013f27ec8e7732f Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 4 May 2026 18:48:54 +0000 Subject: [PATCH 144/148] Fix --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 359664ea7..b86b1242f 100644 --- a/Makefile +++ b/Makefile @@ -35,8 +35,8 @@ GIGL_E2E_TEST_COMPILED_PIPELINE_PATH:=/tmp/gigl/pipeline_${DATE}_${GIT_HASH}.yam GIT_BRANCH:=$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") -# Find all markdown files in the repo except for those in .venv or tools directories. -MD_FILES := $(shell find . -type f -name "*.md" ! -path "*/.venv/*" ! -path "*/tools/*") +# Find all markdown files in the repo except for those in .venv, tools, or cmake cache directories. +MD_FILES := $(shell find . -type f -name "*.md" ! -path "*/.venv/*" ! -path "*/tools/*" ! -path "*/.cache/*") GIGL_ALERT_EMAILS?="" get_ver_hash: From db0a44e9561a4c3611e9581ff8fcc249168f715b Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 4 May 2026 19:34:15 +0000 Subject: [PATCH 145/148] Fix --- gigl-core/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gigl-core/Makefile b/gigl-core/Makefile index 85b5fab68..2cbc48bd6 100644 --- a/gigl-core/Makefile +++ b/gigl-core/Makefile @@ -43,7 +43,7 @@ format_cpp: # WarningsAsErrors: '*', so the warning must be silenced at the compiler level before # clang-tidy ever sees it. check_lint_cpp: build_cpp_extensions - uv run python scripts/run_cpp_lint.py $(CPP_SOURCES_NO_CUDA) + cd $(abspath $(CURDIR)/..) && uv run python gigl-core/scripts/run_cpp_lint.py $(addprefix gigl-core/,$(CPP_SOURCES_NO_CUDA)) fix_lint_cpp: build_cpp_extensions clang-tidy-15 --fix --extra-arg=-Wno-ignored-optimization-argument -p .cache/cmake_build/compile_commands.json $(CPP_SOURCES_NO_CUDA) From 7d3182eeb6446ce3e35910babba990c8e003879d Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 4 May 2026 22:19:27 +0000 Subject: [PATCH 146/148] Add pybind11 back to pyproject.toml (bug fix on main) --- pyproject.toml | 8 ++++---- uv.lock | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ebbc65ea8..de3542607 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,10 +108,10 @@ required-environments = [ no-build-isolation-package = ["gigl-core"] [dependency-groups] -# scikit-build-core is gigl-core's PEP 517 build backend. With no-build-isolation-package -# set, uv does not install [build-system].requires automatically, so it must be present -# in the ambient environment before any gigl-core build (uv sync, uv build, Dockerfiles). -gigl-core-build-backend = ["scikit-build-core>=0.10"] +# These are gigl-core's [build-system].requires. With no-build-isolation-package set, +# uv does not install them automatically, so they must be present in the ambient +# environment before any gigl-core build (uv sync, uv build, Dockerfiles). +gigl-core-build-backend = ["scikit-build-core>=0.10", "pybind11>=2.12"] dev = [ {include-group = "gigl-core-build-backend"}, {include-group = "docs"}, diff --git a/uv.lock b/uv.lock index b8303f693..afa760197 100644 --- a/uv.lock +++ b/uv.lock @@ -784,6 +784,7 @@ dev = [ { name = "pandas-stubs" }, { name = "parameterized" }, { name = "pre-commit" }, + { name = "pybind11" }, { name = "pydata-sphinx-theme" }, { name = "ruff" }, { name = "scikit-build-core" }, @@ -818,6 +819,7 @@ docs = [ { name = "sphinx-tabs" }, ] gigl-core-build-backend = [ + { name = "pybind11" }, { name = "scikit-build-core" }, ] lint = [ @@ -910,6 +912,7 @@ dev = [ { name = "pandas-stubs", specifier = "==2.2.2.240807" }, { name = "parameterized", specifier = "==0.9.0" }, { name = "pre-commit", specifier = "==3.3.2" }, + { name = "pybind11", specifier = ">=2.12" }, { name = "pydata-sphinx-theme", specifier = "==0.16.1" }, { name = "ruff", specifier = "==0.15.10" }, { name = "scikit-build-core", specifier = ">=0.10" }, @@ -943,7 +946,10 @@ docs = [ { name = "sphinx-rtd-theme", specifier = "==2.0.0" }, { name = "sphinx-tabs", specifier = "==3.4.5" }, ] -gigl-core-build-backend = [{ name = "scikit-build-core", specifier = ">=0.10" }] +gigl-core-build-backend = [ + { name = "pybind11", specifier = ">=2.12" }, + { name = "scikit-build-core", specifier = ">=0.10" }, +] lint = [ { name = "mdformat", specifier = "==0.7.22" }, { name = "mdformat-tables", specifier = "==1.0.0" }, @@ -3070,6 +3076,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] +[[package]] +name = "pybind11" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/f0/35145a3c3baffeef55d4b8324caa33abaa8fa56ab345ecd4b2211d09163e/pybind11-3.0.4.tar.gz", hash = "sha256:3286b59c8a774b9ee650169302dd5a4eedc30a8617905a0560dd8ee44775130c", size = 589533, upload-time = "2026-04-19T03:08:15.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/06/c3a23c9a0263b136c519f033a58d4641e73065fefc7754e9667ec206d992/pybind11-3.0.4-py3-none-any.whl", hash = "sha256:961720ee652da51d531b7b2451a6bd2bc042b0106e6d9baa48ecb7d58034ce63", size = 314166, upload-time = "2026-04-19T03:08:14.091Z" }, +] + [[package]] name = "pycparser" version = "2.23" From f50dfa48e52ac9b8fba7d12153ab02507883784d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 4 May 2026 22:48:35 +0000 Subject: [PATCH 147/148] [AUTOMATED] Update dep.vars, and other relevant files with new image names --- .github/cloud_builder/run_command_on_active_checkout.yaml | 2 +- gigl/dep_vars.env | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/cloud_builder/run_command_on_active_checkout.yaml b/.github/cloud_builder/run_command_on_active_checkout.yaml index d99c024a3..5c11c5207 100644 --- a/.github/cloud_builder/run_command_on_active_checkout.yaml +++ b/.github/cloud_builder/run_command_on_active_checkout.yaml @@ -3,7 +3,7 @@ substitutions: options: logging: CLOUD_LOGGING_ONLY steps: - - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 + - name: us-central1-docker.pkg.dev/external-snap-ci-github-gigl/gigl-base-images/gigl-builder:7d3182eeb6446ce3e35910babba990c8e003879d.109.1 entrypoint: /bin/bash args: - -c diff --git a/gigl/dep_vars.env b/gigl/dep_vars.env index 4b28e38b7..6f6ee5584 100644 --- a/gigl/dep_vars.env +++ b/gigl/dep_vars.env @@ -1,7 +1,7 @@ # Note this file only supports static key value pairs so it can be loaded by make, bash, python, and sbt without any additional parsing. -DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 -DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 -DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:b598f3d72eee47f5513dcb39460944459a0a012f.108.1 +DOCKER_LATEST_BASE_CUDA_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cuda-base:7d3182eeb6446ce3e35910babba990c8e003879d.109.1 +DOCKER_LATEST_BASE_CPU_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-cpu-base:7d3182eeb6446ce3e35910babba990c8e003879d.109.1 +DOCKER_LATEST_BASE_DATAFLOW_IMAGE_NAME_WITH_TAG=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/gigl-dataflow-base:7d3182eeb6446ce3e35910babba990c8e003879d.109.1 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CUDA=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cuda:0.2.0 DEFAULT_GIGL_RELEASE_SRC_IMAGE_CPU=us-central1-docker.pkg.dev/external-snap-ci-github-gigl/public-gigl/src-cpu:0.2.0 From 46194a32ed1d42273b0dc3dd3df494e13e094dc4 Mon Sep 17 00:00:00 2001 From: mkolodner Date: Mon, 4 May 2026 23:35:13 +0000 Subject: [PATCH 148/148] Fix --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3325d1c98..0855887be 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,7 +59,7 @@ jobs: run: | # Remove stale cmake cache from previous runs on self-hosted runners. rm -rf gigl-core/.cache/cmake_build - uv build --wheel gigl-core/ --locked + uv build --wheel gigl-core/ - name: Publish gigl-core wheel working-directory: gigl-core @@ -73,5 +73,5 @@ jobs: # when gigl becomes available. - name: Build and publish gigl wheel run: | - uv build --wheel --locked + uv build --wheel uv publish --publish-url ${{ matrix.publish-url }} --username oauth2accesstoken --keyring-provider subprocess