From 95ca948569836045cf7d95a6c9234fc7f5df4533 Mon Sep 17 00:00:00 2001 From: kartikeyamandhar Date: Sun, 29 Mar 2026 22:28:03 -0700 Subject: [PATCH 01/20] Add Neo4j GraphRAG example with TMDB movies dataset Full pipeline expressed as Hamilton DAGs: - Ingestion: TMDB JSON -> Neo4j via batched Cypher MERGE (4,803 movies, 111k+ person edges, 20 genres, 5,047 companies) - Embedding: OpenAI text-embedding-3-small on Movie nodes with Neo4j cosine vector index - Retrieval: semantic entity resolution + 4-strategy routing (VECTOR / CYPHER / AGGREGATE / HYBRID) with direct Neo4j Cypher - Generation: gpt-4o with graph-grounded context - Passes 40 test queries across all retrieval categories - DAG visualisations in docs/images/ --- .../LLM_Workflows/neo4j_graph_rag/.gitignore | 27 + .../LLM_Workflows/neo4j_graph_rag/README.md | 205 +++++ .../neo4j_graph_rag/data/README.md | 38 + .../neo4j_graph_rag/data/data_refine.py | 10 + .../neo4j_graph_rag/docker-compose.yml | 42 + .../neo4j_graph_rag/embed_module.py | 168 ++++ .../neo4j_graph_rag/generation_module.py | 93 +++ .../neo4j_graph_rag/graph_schema.py | 108 +++ .../neo4j_graph_rag/ingest_module.py | 326 ++++++++ .../neo4j_graph_rag/requirements.txt | 10 + .../neo4j_graph_rag/retrieval_module.py | 789 ++++++++++++++++++ examples/LLM_Workflows/neo4j_graph_rag/run.py | 242 ++++++ 12 files changed, 2058 insertions(+) create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/.gitignore create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/README.md create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/data/README.md create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/docker-compose.yml create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/embed_module.py create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/generation_module.py create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/graph_schema.py create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/ingest_module.py create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/requirements.txt create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/retrieval_module.py create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/run.py diff --git a/examples/LLM_Workflows/neo4j_graph_rag/.gitignore b/examples/LLM_Workflows/neo4j_graph_rag/.gitignore new file mode 100644 index 000000000..7a8422825 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/.gitignore @@ -0,0 +1,27 @@ +# Environment +.env + +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +venv/ +.venv/ + +# Data files (download separately per data/README.md) +data/*.json +data/*.csv + +# DAG visualisations are committed — ignore regenerated copies at root +ingest_dag.png +embed_dag.png +rag_dag.png + +# Neo4j +*.dump + +# OS +.DS_Store +Thumbs.db diff --git a/examples/LLM_Workflows/neo4j_graph_rag/README.md b/examples/LLM_Workflows/neo4j_graph_rag/README.md new file mode 100644 index 000000000..69273c55d --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/README.md @@ -0,0 +1,205 @@ + + +# Neo4j GraphRAG — TMDB Movies + +A full GraphRAG pipeline over a movie knowledge graph stored in Neo4j, +built entirely with Apache Hamilton. Ingestion, embedding, and retrieval +are each expressed as first-class Hamilton DAGs — dependencies declared +through function signatures, execution graph built automatically. + +## Hamilton DAG visualisations + +Run `--visualise` on any mode to regenerate these from source without +executing the pipeline. + +### Ingestion DAG + +```bash +python run.py --mode ingest --visualise +``` + +![Ingestion DAG](docs/images/ingest_dag.png) + +Raw TMDB JSON flows through parsing nodes into batched Neo4j writes. +Hamilton automatically parallelises the four independent branches +(movies, genres, companies, person edges) from the shared `raw_movies` +and `raw_credits` inputs. + +--- + +### Embedding DAG + +```bash +python run.py --mode embed --visualise +``` + +![Embedding DAG](docs/images/embed_dag.png) + +Movie texts are fetched from Neo4j, batched through the OpenAI embeddings +API, written back to Movie nodes, and a cosine vector index is created. + +--- + +### Retrieval + Generation DAG + +```bash +python run.py --mode query --visualise +``` + +![RAG DAG](docs/images/rag_dag.png) + +The full 13-node RAG pipeline. Hamilton wires all dependencies from +function signatures — no manual orchestration: + +``` +user_query + openai_api_key + neo4j_driver + -> query_intent classify into VECTOR / CYPHER / AGGREGATE / HYBRID + -> entity_extraction extract persons, movies, genres, companies, filters + -> entity_resolution fuzzy-match each entity against the live graph + -> query_embedding embed query (VECTOR / HYBRID only) + -> vector_results cosine similarity search (VECTOR / HYBRID only) + -> cypher_query LLM generates Cypher from resolved entities + -> cypher_results execute Cypher against Neo4j + -> merged_results combine both retrieval paths + -> retrieved_context format as numbered plain-text records + -> system_prompt inject context into LLM system prompt + -> prompt_messages assemble message list + -> answer gpt-4o generates final answer +``` + +## What it demonstrates + +**Ingestion DAG** (`ingest_module.py`) +Loads TMDB JSON, parses entities and relationships, writes to Neo4j via +batched Cypher `MERGE`. + +**Embedding DAG** (`embed_module.py`) +Computes OpenAI `text-embedding-3-small` embeddings over title + overview, +writes vectors to Movie nodes, creates a Neo4j cosine vector index. + +**Retrieval DAG** (`retrieval_module.py`) +Classifies each query into one of four strategies, resolves named entities +against the graph to get canonical names, then executes retrieval: + +| Strategy | When used | How it retrieves | +|-------------|----------------------------------|-----------------------------------------------| +| `VECTOR` | Thematic / semantic queries | Cosine vector search over Movie embeddings | +| `CYPHER` | Relational / factual queries | LLM-generated Cypher with resolved entities | +| `AGGREGATE` | Counting / ranking queries | Aggregation Cypher with popularity guard | +| `HYBRID` | Filtered + semantic queries | CYPHER + VECTOR, results merged | + +The semantic entity resolution layer looks up every extracted entity in +Neo4j before generating Cypher, so "Warner Bros movies" always resolves +to the canonical `"Warner Bros."` name in the graph. + +**Generation DAG** (`generation_module.py`) +Formats retrieved records into a grounded system prompt and calls gpt-4o. + +## Knowledge graph schema + +``` +(:Movie {id, title, release_date, overview, popularity, vote_average}) +(:Person {id, name}) +(:Genre {name}) +(:ProductionCompany {id, name}) + +(:Person)-[:ACTED_IN {order, character}]->(:Movie) +(:Person)-[:DIRECTED]->(:Movie) +(:Movie)-[:IN_GENRE]->(:Genre) +(:Movie)-[:PRODUCED_BY]->(:ProductionCompany) +``` + +Dataset: 4,803 movies · 56,603 persons · 106,257 ACTED_IN · 5,166 DIRECTED · 20 genres · 5,047 companies + +## Prerequisites + +- Docker +- Python 3.10+ +- OpenAI API key (`gpt-4o` access) +- TMDB dataset (see `data/README.md`) + +## Setup + +### 1. Start Neo4j + +```bash +docker compose up -d +``` + +Neo4j browser: http://localhost:7474 (user: `neo4j`, password: `password`) + +### 2. Install dependencies + +```bash +python -m venv venv +source venv/bin/activate +pip install -r requirements.txt +``` + +### 3. Configure environment + +```bash +cp .env.example .env +# edit .env — add your OPENAI_API_KEY +``` + +### 4. Download the dataset + +Follow `data/README.md` to download and convert the TMDB dataset. + +## Running + +```bash +# Step 1 — load graph (takes ~5 seconds) +python run.py --mode ingest + +# Step 2 — compute and store embeddings (takes ~2 minutes) +python run.py --mode embed + +# Step 3 — query +python run.py --mode query --question "Who directed Inception?" +python run.py --mode query --question "Which movies did Tom Hanks and Robin Wright appear in together?" +python run.py --mode query --question "Which production company made the most action movies?" +python run.py --mode query --question "Recommend movies similar to Inception" +python run.py --mode query --question "Find me war films rated above 7.5" +python run.py --mode query --question "Which actors appeared in both a Christopher Nolan and a Steven Spielberg film?" +``` + +## Project structure + +``` +neo4j_graph_rag/ +├── docker-compose.yml Neo4j 5 + APOC +├── requirements.txt +├── .env.example +├── graph_schema.py Node/relationship definitions and Cypher constraints +├── ingest_module.py Hamilton DAG: JSON -> Neo4j +├── embed_module.py Hamilton DAG: Movie nodes -> embeddings -> vector index +├── retrieval_module.py Hamilton DAG: query -> entity resolution -> retrieval +├── generation_module.py Hamilton DAG: context + query -> gpt-4o -> answer +├── run.py Entry point wiring all three pipelines +├── docs/ +│ └── images/ +│ ├── ingest_dag.png +│ ├── embed_dag.png +│ └── rag_dag.png +└── data/ + └── README.md Dataset download and conversion instructions +``` \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/data/README.md b/examples/LLM_Workflows/neo4j_graph_rag/data/README.md new file mode 100644 index 000000000..790f19820 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/data/README.md @@ -0,0 +1,38 @@ +# Data + +This example uses the [TMDB 5000 Movie Dataset](https://www.kaggle.com/datasets/tmdb/tmdb-movie-metadata) from Kaggle. + +## Download + +1. Create a free Kaggle account at https://www.kaggle.com +2. Go to https://www.kaggle.com/datasets/tmdb/tmdb-movie-metadata +3. Click **Download** and unzip the archive +4. Place the following two files in this `data/` folder: + +``` +data/ +├── tmdb_5000_movies.json +└── tmdb_5000_credits.json +``` + +## Note on file format + +The Kaggle archive ships the files as CSV (`tmdb_5000_movies.csv`, `tmdb_5000_credits.csv`). +Several columns contain JSON strings (genres, cast, crew, production_companies). + +Convert them to JSON before running ingestion: + +```python +import pandas as pd, json + +movies = pd.read_csv("tmdb_5000_movies.csv") +credits = pd.read_csv("tmdb_5000_credits.csv") + +with open("tmdb_5000_movies.json", "w") as f: + json.dump(movies.to_dict(orient="records"), f) + +with open("tmdb_5000_credits.json", "w") as f: + json.dump(credits.to_dict(orient="records"), f) +``` + +Run this script once from inside the `data/` folder, then proceed with `python run.py --mode ingest`. \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py b/examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py new file mode 100644 index 000000000..5d1dc1884 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py @@ -0,0 +1,10 @@ +import pandas as pd, json + +movies = pd.read_csv("examples/LLM_Workflows/neo4j_graph_rag/data/tmdb_5000_movies.csv") +credits = pd.read_csv("examples/LLM_Workflows/neo4j_graph_rag/data/tmdb_5000_credits.csv") + +with open("examples/LLM_Workflows/neo4j_graph_rag/data/tmdb_5000_movies.json", "w") as f: + json.dump(movies.to_dict(orient="records"), f) + +with open("examples/LLM_Workflows/neo4j_graph_rag/data/tmdb_5000_credits.json", "w") as f: + json.dump(credits.to_dict(orient="records"), f) \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/docker-compose.yml b/examples/LLM_Workflows/neo4j_graph_rag/docker-compose.yml new file mode 100644 index 000000000..b41df8671 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/docker-compose.yml @@ -0,0 +1,42 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +services: + neo4j: + image: neo4j:5.18.0 + container_name: neo4j_graph_rag + ports: + - "7474:7474" # Browser UI + - "7687:7687" # Bolt protocol + environment: + - NEO4J_AUTH=neo4j/password + - NEO4J_PLUGINS=["apoc"] + - NEO4J_apoc_export_file_enabled=true + - NEO4J_apoc_import_file_enabled=true + - NEO4J_dbms_security_procedures_unrestricted=apoc.* + volumes: + - neo4j_data:/data + - neo4j_logs:/logs + healthcheck: + test: ["CMD", "cypher-shell", "-u", "neo4j", "-p", "password", "RETURN 1"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + neo4j_data: + neo4j_logs: \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/embed_module.py b/examples/LLM_Workflows/neo4j_graph_rag/embed_module.py new file mode 100644 index 000000000..2dd5ecd3d --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/embed_module.py @@ -0,0 +1,168 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Hamilton embedding DAG. + +Fetches Movie nodes from Neo4j, computes OpenAI embeddings over +title + overview text, writes embeddings back to each node, and +creates a Neo4j vector index for use during retrieval. + +Run this once after ingestion and before querying. + +DAG flow: + neo4j_driver + openai_api_key + -> movie_texts + -> embedding_client + -> movie_embeddings + -> vector_index + -> embedding_summary +""" + +import logging + +import openai +from neo4j import Driver + +logger = logging.getLogger(__name__) + +# Shared constants — also imported by retrieval_module.py +VECTOR_INDEX_NAME = "movie_embeddings" +EMBEDDING_MODEL = "text-embedding-3-small" +EMBEDDING_DIMENSIONS = 1536 +BATCH_SIZE = 100 + + +def movie_texts(neo4j_driver: Driver) -> list[dict]: + """ + Fetch all Movie nodes and build embedding text from title + overview. + Returns list of dicts with keys: id, text. + """ + query = """ + MATCH (m:Movie) + WHERE m.title IS NOT NULL + RETURN m.id AS id, + m.title AS title, + coalesce(m.overview, '') AS overview + """ + with neo4j_driver.session() as session: + rows = session.run(query).data() + + texts = [ + { + "id": row["id"], + "text": f"{row['title']}. {row['overview']}".strip(), + } + for row in rows + if row["id"] is not None + ] + logger.info("Fetched %d movie texts for embedding", len(texts)) + return texts + + +def embedding_client(openai_api_key: str) -> openai.OpenAI: + """Initialise the OpenAI client for embedding calls.""" + return openai.OpenAI(api_key=openai_api_key) + + +def movie_embeddings( + movie_texts: list[dict], + embedding_client: openai.OpenAI, +) -> list[dict]: + """ + Compute OpenAI embeddings for all movie texts in batches of BATCH_SIZE. + Returns list of dicts with keys: id, embedding. + """ + results = [] + total = len(movie_texts) + + for i in range(0, total, BATCH_SIZE): + batch = movie_texts[i : i + BATCH_SIZE] + response = embedding_client.embeddings.create( + model=EMBEDDING_MODEL, + input=[item["text"] for item in batch], + ) + for item, emb_obj in zip(batch, response.data): + results.append({"id": item["id"], "embedding": emb_obj.embedding}) + + logger.info("Embedded batch %d-%d of %d", i, min(i + BATCH_SIZE, total), total) + + logger.info("Computed %d embeddings", len(results)) + return results + + +def vector_index( + movie_embeddings: list[dict], + neo4j_driver: Driver, +) -> str: + """ + Write embeddings to Movie nodes in Neo4j and create a cosine + vector index named VECTOR_INDEX_NAME over the embedding property. + Returns the index name. + """ + write_query = """ + UNWIND $batch AS row + MATCH (m:Movie {id: row.id}) + SET m.embedding = row.embedding + """ + total = len(movie_embeddings) + with neo4j_driver.session() as session: + for i in range(0, total, BATCH_SIZE): + batch = movie_embeddings[i : i + BATCH_SIZE] + session.run(write_query, {"batch": batch}) + logger.info( + "Wrote embeddings to nodes %d-%d of %d", + i, + min(i + BATCH_SIZE, total), + total, + ) + + session.run(f"DROP INDEX {VECTOR_INDEX_NAME} IF EXISTS") + session.run( + f""" + CREATE VECTOR INDEX {VECTOR_INDEX_NAME} + FOR (m:Movie) + ON m.embedding + OPTIONS {{ + indexConfig: {{ + `vector.dimensions`: {EMBEDDING_DIMENSIONS}, + `vector.similarity_function`: 'cosine' + }} + }} + """ + ) + logger.info("Created vector index '%s'", VECTOR_INDEX_NAME) + + return VECTOR_INDEX_NAME + + +def embedding_summary( + movie_embeddings: list[dict], + vector_index: str, +) -> dict: + """ + Collect embedding statistics and return a summary. + Terminal node of the embedding DAG. + """ + summary = { + "embeddings_written": len(movie_embeddings), + "vector_index": vector_index, + "model": EMBEDDING_MODEL, + "dimensions": EMBEDDING_DIMENSIONS, + } + logger.info("Embedding complete: %s", summary) + return summary \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/generation_module.py b/examples/LLM_Workflows/neo4j_graph_rag/generation_module.py new file mode 100644 index 000000000..eee8b078d --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/generation_module.py @@ -0,0 +1,93 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Hamilton generation DAG. + +Takes the retrieved context from the retrieval DAG and the original +user query, constructs a grounded system prompt, and calls gpt-4o +to produce an answer. + +DAG flow: + retrieved_context + user_query + query_intent + -> system_prompt + -> prompt_messages + -> answer +""" + +import logging + +import openai + +logger = logging.getLogger(__name__) + +SYSTEM_TEMPLATE = """You are a movie database assistant. \ +The numbered results below are pre-filtered database records that \ +directly answer the user's question. Each record is already the \ +correct answer — do not question whether it matches the query. + +Rules: +- "Movie: X" means X is a film title. List it. +- "Actor: X" means X appeared in the relevant films. List them. +- "Director: X" means X is a director. State it. +- The results are already filtered by the user's criteria \ + (company, director, genre, etc.) — do not say the company or \ + director is not specified. +- When asked for a list, list every numbered record. +- When asked yes/no, answer yes/no then cite the relevant record. +- When a single record answers "highest/most/best", state it directly. +- If there are genuinely no records, say so briefly. + +Retrieval strategy: {intent} + +Database records: +{context}""" + + +def system_prompt( + retrieved_context: str, + query_intent: str, +) -> str: + """Build the system prompt by injecting retrieved context and intent metadata.""" + return SYSTEM_TEMPLATE.format( + intent=query_intent, + context=retrieved_context, + ) + + +def prompt_messages(system_prompt: str, user_query: str) -> list[dict]: + """Assemble the message list for the OpenAI chat completion call.""" + return [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_query}, + ] + + +def answer(prompt_messages: list[dict], openai_api_key: str) -> str: + """ + Call gpt-4o with the assembled prompt and return the answer string. + Terminal node of the generation DAG. + """ + client = openai.OpenAI(api_key=openai_api_key) + response = client.chat.completions.create( + model="gpt-4o", + messages=prompt_messages, + temperature=0.0, + ) + result = response.choices[0].message.content + logger.info("Generated answer (%d chars)", len(result)) + return result \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/graph_schema.py b/examples/LLM_Workflows/neo4j_graph_rag/graph_schema.py new file mode 100644 index 000000000..a50d82692 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/graph_schema.py @@ -0,0 +1,108 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Static schema definitions for the TMDB movie knowledge graph. + +Nodes +----- +Movie : id, title, release_date, overview, popularity, vote_average +Person : id, name +Genre : name +ProductionCompany : id, name + +Relationships +------------- +(:Person)-[:ACTED_IN {order: int, character: str}]->(:Movie) +(:Person)-[:DIRECTED]->(:Movie) +(:Movie)-[:IN_GENRE]->(:Genre) +(:Movie)-[:PRODUCED_BY]->(:ProductionCompany) + +Constraints (applied at ingestion time via run.py) +----------- +UNIQUE Movie.id +UNIQUE Person.id +UNIQUE Genre.name +UNIQUE ProductionCompany.id +""" + +# Node labels +NODE_MOVIE = "Movie" +NODE_PERSON = "Person" +NODE_GENRE = "Genre" +NODE_COMPANY = "ProductionCompany" + +# Relationship types +REL_ACTED_IN = "ACTED_IN" +REL_DIRECTED = "DIRECTED" +REL_IN_GENRE = "IN_GENRE" +REL_PRODUCED_BY = "PRODUCED_BY" + +# Properties stored per node type +NODE_PROPERTIES = { + NODE_MOVIE: ["id", "title", "release_date", "overview", "popularity", "vote_average"], + NODE_PERSON: ["id", "name"], + NODE_GENRE: ["name"], + NODE_COMPANY: ["id", "name"], +} + +# Properties stored per relationship type +REL_PROPERTIES = { + REL_ACTED_IN: ["order", "character"], + REL_DIRECTED: [], + REL_IN_GENRE: [], + REL_PRODUCED_BY: [], +} + +# Connectivity map src -> rel -> dest +CONNECTIVITY = [ + (NODE_PERSON, REL_ACTED_IN, NODE_MOVIE), + (NODE_PERSON, REL_DIRECTED, NODE_MOVIE), + (NODE_MOVIE, REL_IN_GENRE, NODE_GENRE), + (NODE_MOVIE, REL_PRODUCED_BY, NODE_COMPANY), +] + +# Cypher constraints to create before ingestion +CONSTRAINTS = [ + f"CREATE CONSTRAINT IF NOT EXISTS FOR (n:{NODE_MOVIE}) REQUIRE n.id IS UNIQUE", + f"CREATE CONSTRAINT IF NOT EXISTS FOR (n:{NODE_PERSON}) REQUIRE n.id IS UNIQUE", + f"CREATE CONSTRAINT IF NOT EXISTS FOR (n:{NODE_GENRE}) REQUIRE n.name IS UNIQUE", + f"CREATE CONSTRAINT IF NOT EXISTS FOR (n:{NODE_COMPANY}) REQUIRE n.id IS UNIQUE", +] + + +def schema_to_prompt() -> str: + """ + Returns a natural-language description of the graph schema + for use in LLM system prompts. + """ + lines = ["The knowledge graph contains the following node types:\n"] + + for label, props in NODE_PROPERTIES.items(): + if props: + lines.append(f" {label}: {', '.join(props)}") + else: + lines.append(f" {label}: (no properties)") + + lines.append("\nThe knowledge graph contains the following relationship types:\n") + + for src, rel, dest in CONNECTIVITY: + props = REL_PROPERTIES.get(rel, []) + prop_str = f" with properties: {', '.join(props)}" if props else "" + lines.append(f" (:{src})-[:{rel}]->(:{dest}){prop_str}") + + return "\n".join(lines) \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/ingest_module.py b/examples/LLM_Workflows/neo4j_graph_rag/ingest_module.py new file mode 100644 index 000000000..ac9de7686 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/ingest_module.py @@ -0,0 +1,326 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Hamilton ingestion DAG for the TMDB movie dataset. + +Input files (place in data/): + - tmdb_5000_movies.json : movie metadata, genres, production companies + - tmdb_5000_credits.json : cast and crew per movie + +The DAG produces a fully populated Neo4j knowledge graph with the schema +defined in graph_schema.py. + +Node types : Movie, Person, Genre, ProductionCompany +Relationships: ACTED_IN, DIRECTED, IN_GENRE, PRODUCED_BY + +DAG flow: + movies_path -> raw_movies -> parsed_movies -> write_movie_nodes + -> genre_records -> write_genre_nodes_and_edges + -> company_records -> write_company_nodes_and_edges + credits_path -> raw_credits -> parsed_credits -> write_person_nodes_and_edges + all writes -> ingestion_summary +""" + +import json +import logging + +from neo4j import Driver + +logger = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# 1. Load raw data +# --------------------------------------------------------------------------- + + +def raw_movies(movies_path: str) -> list[dict]: + """Load raw movie records from the TMDB movies JSON file.""" + with open(movies_path) as f: + data = json.load(f) + logger.info("Loaded %d raw movie records", len(data)) + return data + + +def raw_credits(credits_path: str) -> list[dict]: + """Load raw credit records from the TMDB credits JSON file.""" + with open(credits_path) as f: + data = json.load(f) + logger.info("Loaded %d raw credit records", len(data)) + return data + + +# --------------------------------------------------------------------------- +# 2. Parse movies +# --------------------------------------------------------------------------- + + +def parsed_movies(raw_movies: list[dict]) -> list[dict]: + """ + Extract clean Movie node properties from raw records. + Drops records missing id or title. + """ + movies = [] + for m in raw_movies: + if not m.get("id") or not m.get("title"): + continue + movies.append( + { + "id": int(m["id"]), + "title": str(m["title"]), + "release_date": str(m.get("release_date", "")), + "overview": str(m.get("overview", "")), + "popularity": float(m.get("popularity", 0.0)), + "vote_average": float(m.get("vote_average", 0.0)), + } + ) + logger.info("Parsed %d movies", len(movies)) + return movies + + +def genre_records(raw_movies: list[dict]) -> list[dict]: + """ + Extract (movie_id, genre_name) pairs for IN_GENRE relationships. + Handles both pre-parsed lists and JSON-string encoded genres. + """ + records = [] + for m in raw_movies: + movie_id = m.get("id") + if not movie_id: + continue + genres = m.get("genres", []) + if isinstance(genres, str): + try: + genres = json.loads(genres) + except json.JSONDecodeError: + continue + for g in genres: + if g.get("name"): + records.append({"movie_id": int(movie_id), "genre_name": str(g["name"])}) + logger.info("Extracted %d genre relationships", len(records)) + return records + + +def company_records(raw_movies: list[dict]) -> list[dict]: + """ + Extract (movie_id, company_id, company_name) pairs for PRODUCED_BY relationships. + Handles both pre-parsed lists and JSON-string encoded production_companies. + """ + records = [] + for m in raw_movies: + movie_id = m.get("id") + if not movie_id: + continue + companies = m.get("production_companies", []) + if isinstance(companies, str): + try: + companies = json.loads(companies) + except json.JSONDecodeError: + continue + for c in companies: + if c.get("id") and c.get("name"): + records.append( + { + "movie_id": int(movie_id), + "company_id": int(c["id"]), + "company_name": str(c["name"]), + } + ) + logger.info("Extracted %d production company relationships", len(records)) + return records + + +# --------------------------------------------------------------------------- +# 3. Parse credits +# --------------------------------------------------------------------------- + + +def parsed_credits(raw_credits: list[dict]) -> list[dict]: + """ + Parse credits into a flat list of records containing movie_id, + person details, and role (cast or director only from crew). + Handles both pre-parsed lists and JSON-string encoded cast/crew fields. + """ + records = [] + for c in raw_credits: + movie_id = c.get("id") or c.get("movie_id") + if not movie_id: + continue + + cast = c.get("cast", []) + if isinstance(cast, str): + try: + cast = json.loads(cast) + except json.JSONDecodeError: + cast = [] + for member in cast: + if member.get("id") and member.get("name"): + records.append( + { + "movie_id": int(movie_id), + "person_id": int(member["id"]), + "person_name": str(member["name"]), + "role": "cast", + "character": str(member.get("character", "")), + "order": int(member.get("order", 999)), + } + ) + + crew = c.get("crew", []) + if isinstance(crew, str): + try: + crew = json.loads(crew) + except json.JSONDecodeError: + crew = [] + for member in crew: + if member.get("job") == "Director" and member.get("id") and member.get("name"): + records.append( + { + "movie_id": int(movie_id), + "person_id": int(member["id"]), + "person_name": str(member["name"]), + "role": "director", + "character": "", + "order": -1, + } + ) + + logger.info("Parsed %d credit records", len(records)) + return records + + +# --------------------------------------------------------------------------- +# 4. Write to Neo4j +# --------------------------------------------------------------------------- + + +def _run_batch(session, query: str, batch: list[dict]) -> int: + """Execute a parameterised Cypher UNWIND query for a batch of records.""" + session.run(query, {"batch": batch}) + return len(batch) + + +def write_movie_nodes(parsed_movies: list[dict], neo4j_driver: Driver) -> int: + """MERGE Movie nodes into Neo4j. Returns number of movies written.""" + query = """ + UNWIND $batch AS row + MERGE (m:Movie {id: row.id}) + SET m.title = row.title, + m.release_date = row.release_date, + m.overview = row.overview, + m.popularity = row.popularity, + m.vote_average = row.vote_average + """ + with neo4j_driver.session() as session: + count = _run_batch(session, query, parsed_movies) + logger.info("Wrote %d Movie nodes", count) + return count + + +def write_genre_nodes_and_edges(genre_records: list[dict], neo4j_driver: Driver) -> int: + """MERGE Genre nodes and IN_GENRE relationships. Returns number of edges written.""" + query = """ + UNWIND $batch AS row + MERGE (g:Genre {name: row.genre_name}) + WITH g, row + MATCH (m:Movie {id: row.movie_id}) + MERGE (m)-[:IN_GENRE]->(g) + """ + with neo4j_driver.session() as session: + count = _run_batch(session, query, genre_records) + logger.info("Wrote %d IN_GENRE edges", count) + return count + + +def write_company_nodes_and_edges(company_records: list[dict], neo4j_driver: Driver) -> int: + """MERGE ProductionCompany nodes and PRODUCED_BY relationships.""" + query = """ + UNWIND $batch AS row + MERGE (c:ProductionCompany {id: row.company_id}) + SET c.name = row.company_name + WITH c, row + MATCH (m:Movie {id: row.movie_id}) + MERGE (m)-[:PRODUCED_BY]->(c) + """ + with neo4j_driver.session() as session: + count = _run_batch(session, query, company_records) + logger.info("Wrote %d PRODUCED_BY edges", count) + return count + + +def write_person_nodes_and_edges(parsed_credits: list[dict], neo4j_driver: Driver) -> int: + """ + MERGE Person nodes and ACTED_IN / DIRECTED relationships. + Returns total number of relationships written. + """ + acted_in_query = """ + UNWIND $batch AS row + MERGE (p:Person {id: row.person_id}) + SET p.name = row.person_name + WITH p, row + MATCH (m:Movie {id: row.movie_id}) + MERGE (p)-[r:ACTED_IN {order: row.order}]->(m) + SET r.character = row.character + """ + directed_query = """ + UNWIND $batch AS row + MERGE (p:Person {id: row.person_id}) + SET p.name = row.person_name + WITH p, row + MATCH (m:Movie {id: row.movie_id}) + MERGE (p)-[:DIRECTED]->(m) + """ + cast_records = [r for r in parsed_credits if r["role"] == "cast"] + director_records = [r for r in parsed_credits if r["role"] == "director"] + + with neo4j_driver.session() as session: + _run_batch(session, acted_in_query, cast_records) + _run_batch(session, directed_query, director_records) + + total = len(cast_records) + len(director_records) + logger.info( + "Wrote %d ACTED_IN and %d DIRECTED edges", + len(cast_records), + len(director_records), + ) + return total + + +# --------------------------------------------------------------------------- +# 5. Terminal node +# --------------------------------------------------------------------------- + + +def ingestion_summary( + write_movie_nodes: int, + write_genre_nodes_and_edges: int, + write_company_nodes_and_edges: int, + write_person_nodes_and_edges: int, +) -> dict: + """ + Collect write counts from all upstream nodes and return a summary. + Terminal node of the ingestion DAG. + """ + summary = { + "movies": write_movie_nodes, + "genre_edges": write_genre_nodes_and_edges, + "company_edges": write_company_nodes_and_edges, + "person_edges": write_person_nodes_and_edges, + } + logger.info("Ingestion complete: %s", summary) + return summary \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/requirements.txt b/examples/LLM_Workflows/neo4j_graph_rag/requirements.txt new file mode 100644 index 000000000..8c44a1add --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/requirements.txt @@ -0,0 +1,10 @@ +sf-hamilton>=1.73.0 +neo4j>=5.18.0 +llama-index>=0.10.0 +llama-index-graph-stores-neo4j>=0.2.0 +llama-index-llms-openai>=0.1.0 +llama-index-embeddings-openai>=0.1.0 +openai>=1.30.0 +pandas>=2.0.0 +python-dotenv>=1.0.0 +tqdm>=4.66.0 \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/retrieval_module.py b/examples/LLM_Workflows/neo4j_graph_rag/retrieval_module.py new file mode 100644 index 000000000..3c045d343 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/retrieval_module.py @@ -0,0 +1,789 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Hamilton retrieval DAG — semantic entity resolution + multi-strategy GraphRAG. + +Pipeline: + 1. query_intent — classify into VECTOR / CYPHER / AGGREGATE / HYBRID + 2. entity_extraction — LLM extracts named entities from the query + 3. entity_resolution — each entity is looked up in Neo4j to get its + canonical form (exact name, genre spelling, date format) + 4. cypher_query — Cypher is generated using resolved entities, not raw text + 5. cypher_results — execute and return rows + 6. vector_results — semantic similarity search (VECTOR / HYBRID only) + 7. merged_results — combine both paths + 8. retrieved_context — format for generation DAG +""" + +import json +import logging + +import openai +from neo4j import Driver + +from embed_module import EMBEDDING_MODEL, VECTOR_INDEX_NAME +from graph_schema import schema_to_prompt + +logger = logging.getLogger(__name__) + +TOP_K = 8 +MAX_CAST = 8 +MAX_RETRIES = 2 +SCHEMA_PROMPT = schema_to_prompt() + +# --------------------------------------------------------------------------- +# Cypher examples used in generation prompt +# --------------------------------------------------------------------------- + +CYPHER_EXAMPLES = """ +-- Direct lookup (always return person/movie names explicitly) +MATCH (d:Person)-[:DIRECTED]->(m:Movie) +WHERE toLower(m.title) = toLower('Inception') +RETURN m.title AS movie, d.name AS director, m.release_date, m.vote_average + +-- Actor filmography (always alias person name) +MATCH (p:Person)-[:ACTED_IN]->(m:Movie) +WHERE p.name = 'Tom Hanks' +RETURN p.name AS actor, m.title AS movie, m.release_date +ORDER BY m.release_date DESC +LIMIT 20 + +-- Director filmography +MATCH (p:Person)-[:DIRECTED]->(m:Movie) +WHERE p.name = 'Christopher Nolan' +RETURN p.name AS director, m.title AS movie, m.release_date, m.vote_average +ORDER BY m.release_date + +-- Co-occurrence (use exact resolved names) +MATCH (a:Person {name: 'Tom Hanks'})-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(b:Person {name: 'Robin Wright'}) +RETURN m.title AS movie, m.release_date + +-- Aggregation with minimum count to avoid single-film outliers +MATCH (d:Person)-[:DIRECTED]->(m:Movie) +WITH d, avg(m.vote_average) AS avg_rating, count(m) AS film_count +WHERE film_count >= 3 +RETURN d.name AS director, avg_rating, film_count +ORDER BY avg_rating DESC +LIMIT 10 + +-- Production company (use exact resolved name) +MATCH (c:ProductionCompany {name: 'Warner Bros. Pictures'})<-[:PRODUCED_BY]-(m:Movie) +RETURN m.title AS movie, m.release_date +ORDER BY m.release_date DESC +LIMIT 20 + +-- Genre filter (use exact resolved genre name, string date comparison) +MATCH (m:Movie)-[:IN_GENRE]->(g:Genre {name: 'Comedy'}) +WHERE m.vote_average > 7 + AND m.release_date > '2010-12-31' +RETURN m.title AS movie, m.release_date, m.vote_average +ORDER BY m.vote_average DESC +LIMIT 20 + +-- Multi-hop: always include connecting film titles for context +MATCH (a:Person)-[:ACTED_IN]->(m1:Movie)<-[:DIRECTED]-(d1:Person {name: 'Christopher Nolan'}) + ,(a)-[:ACTED_IN]->(m2:Movie)<-[:DIRECTED]-(d2:Person {name: 'Steven Spielberg'}) +RETURN DISTINCT a.name AS actor, m1.title AS nolan_film, m2.title AS spielberg_film +LIMIT 20 + +-- Hybrid: director + genre + rating +MATCH (d:Person {name: 'James Cameron'})-[:DIRECTED]->(m:Movie)-[:IN_GENRE]->(g:Genre {name: 'Science Fiction'}) +RETURN m.title AS movie, m.vote_average, d.name AS director +ORDER BY m.vote_average DESC +LIMIT 20 + +-- Highest rated overall or by genre (ALWAYS add popularity > 5 to exclude obscure films) +MATCH (m:Movie)-[:IN_GENRE]->(g:Genre {name: 'Drama'}) +WHERE m.popularity > 5 +RETURN m.title AS movie, m.vote_average +ORDER BY m.vote_average DESC +LIMIT 1 + +-- Highest rated film overall (ALWAYS add popularity > 5) +MATCH (m:Movie) +WHERE m.popularity > 5 +RETURN m.title AS movie, m.vote_average +ORDER BY m.vote_average DESC +LIMIT 1 +""" + + +# --------------------------------------------------------------------------- +# 1. Classify query intent +# --------------------------------------------------------------------------- + +def query_intent(user_query: str, openai_api_key: str) -> str: + """ + Classify the user query into one of four retrieval strategies: + VECTOR — thematic/semantic (recommend, find similar, what movies about X) + CYPHER — relational facts (who directed X, filmography, co-stars, direct lookup) + AGGREGATE — counting/ranking across the dataset + HYBRID — needs both graph facts AND semantic similarity / filtering + """ + system = """You are a query classifier for a movie knowledge graph. +Classify the user query into exactly one of these retrieval strategies: + +VECTOR — thematic or semantic: recommendations, "find movies like X", + "movies about space", "psychological thrillers" +CYPHER — relational or factual: "who directed X", "what movies did actor Y appear in", + "did A and B appear together", "movies by director Z", + "what year was X released", "who starred in X" +AGGREGATE — counting, ranking, aggregation: "which company made the most action movies", + "highest rated drama", "director with highest average rating", + "how many movies did X direct" +HYBRID — needs both graph traversal AND filtering/rating: + "highest rated sci-fi films by James Cameron", + "Tom Hanks movies rated above 7.5", + "comedy films after 2010 rated above 7" + +Reply with ONLY one word: VECTOR, CYPHER, AGGREGATE, or HYBRID.""" + + client = openai.OpenAI(api_key=openai_api_key) + response = client.chat.completions.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": user_query}, + ], + temperature=0.0, + max_tokens=10, + ) + intent = response.choices[0].message.content.strip().upper() + if intent not in ("VECTOR", "CYPHER", "AGGREGATE", "HYBRID"): + logger.warning("Unexpected intent '%s', defaulting to HYBRID", intent) + intent = "HYBRID" + logger.info("Query intent: %s", intent) + return intent + + +# --------------------------------------------------------------------------- +# 2. Entity extraction +# --------------------------------------------------------------------------- + +def entity_extraction( + user_query: str, + openai_api_key: str, + query_intent: str, +) -> dict: + """ + Extract named entities from the user query as a structured dict. + Returns empty dict for VECTOR queries (no entity resolution needed). + + Entity types extracted: + movies : list of movie titles mentioned + persons : list of person names (actors, directors) + genres : list of genres mentioned + companies : list of production company names mentioned + year_after : year string if query filters by "after YYYY" + year_before : year string if query filters by "before YYYY" + rating_above: float if query filters by minimum rating + rating_below: float if query filters by maximum rating + """ + if query_intent == "VECTOR": + logger.info("Skipping entity extraction for VECTOR intent") + return {} + + system = """You are an entity extractor for a movie knowledge graph query system. + +Extract all named entities from the user query and return a JSON object with these keys +(omit keys that are not present in the query): + +{ + "movies": ["title1", "title2"], + "persons": ["name1", "name2"], + "genres": ["genre1"], + "companies": ["company name"], + "year_after": "YYYY", + "year_before": "YYYY", + "rating_above": 7.5, + "rating_below": 8.0 +} + +Rules: +- Extract exactly what is in the query, do not normalise or correct spellings yet +- If a name could be an actor or director, put it in "persons" +- Return ONLY valid JSON, no explanation, no markdown fences""" + + client = openai.OpenAI(api_key=openai_api_key) + response = client.chat.completions.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": user_query}, + ], + temperature=0.0, + max_tokens=300, + ) + raw = response.choices[0].message.content.strip() + if raw.startswith("```"): + raw = "\n".join(raw.split("\n")[1:]) + if raw.endswith("```"): + raw = "\n".join(raw.split("\n")[:-1]) + try: + entities = json.loads(raw) + except json.JSONDecodeError: + logger.warning("Failed to parse entity extraction response: %s", raw) + entities = {} + + logger.info("Extracted entities: %s", entities) + return entities + + +# --------------------------------------------------------------------------- +# 3. Entity resolution — look up canonical forms in Neo4j +# --------------------------------------------------------------------------- + +def _resolve_persons(names: list[str], session) -> dict[str, str]: + """Fuzzy-match person names against the graph, return {input: canonical}.""" + resolved = {} + for name in names: + result = session.run( + """ + MATCH (p:Person) + WHERE toLower(p.name) CONTAINS toLower($name) + RETURN p.name AS name + ORDER BY size(p.name) + LIMIT 1 + """, + {"name": name}, + ).single() + if result: + resolved[name] = result["name"] + logger.info("Resolved person '%s' -> '%s'", name, result["name"]) + else: + resolved[name] = name + logger.warning("Could not resolve person '%s', using as-is", name) + return resolved + + +def _resolve_movies(titles: list[str], session) -> dict[str, str]: + """Fuzzy-match movie titles against the graph, return {input: canonical}.""" + resolved = {} + for title in titles: + result = session.run( + """ + MATCH (m:Movie) + WHERE toLower(m.title) CONTAINS toLower($title) + RETURN m.title AS title + ORDER BY size(m.title) + LIMIT 1 + """, + {"title": title}, + ).single() + if result: + resolved[title] = result["title"] + logger.info("Resolved movie '%s' -> '%s'", title, result["title"]) + else: + resolved[title] = title + logger.warning("Could not resolve movie '%s', using as-is", title) + return resolved + + +GENRE_ALIASES = { + "sci-fi": "Science Fiction", + "scifi": "Science Fiction", + "science fiction": "Science Fiction", + "rom-com": "Romance", + "romcom": "Romance", + "rom com": "Romance", + "action-adventure": "Action", + "documentary": "Documentary", + "doc": "Documentary", + "animated": "Animation", + "animation": "Animation", + "anime": "Animation", + "horror": "Horror", + "comedy": "Comedy", + "drama": "Drama", + "thriller": "Thriller", + "western": "Western", + "fantasy": "Fantasy", + "mystery": "Mystery", + "adventure": "Adventure", + "crime": "Crime", + "family": "Family", + "history": "History", + "music": "Music", + "romance": "Romance", + "war": "War", + "tv movie": "TV Movie", +} + + +def _resolve_genres(genres: list[str], session) -> dict[str, str]: + """ + Resolve genre names to their canonical form in the graph. + First checks a local alias map for common abbreviations (e.g. sci-fi), + then falls back to fuzzy Neo4j lookup. + Returns {input: canonical}. + """ + resolved = {} + for genre in genres: + # Check alias map first + alias = GENRE_ALIASES.get(genre.lower()) + if alias: + resolved[genre] = alias + logger.info("Resolved genre '%s' -> '%s' (alias map)", genre, alias) + continue + + # Fall back to fuzzy Neo4j lookup + result = session.run( + """ + MATCH (g:Genre) + WHERE toLower(g.name) CONTAINS toLower($genre) + RETURN g.name AS name + LIMIT 1 + """, + {"genre": genre}, + ).single() + if result: + resolved[genre] = result["name"] + logger.info("Resolved genre '%s' -> '%s'", genre, result["name"]) + else: + resolved[genre] = genre + logger.warning("Could not resolve genre '%s', using as-is", genre) + return resolved + + +def _resolve_companies(companies: list[str], session) -> dict[str, str]: + """Fuzzy-match company names against the graph, return {input: canonical}.""" + resolved = {} + for company in companies: + result = session.run( + """ + MATCH (c:ProductionCompany) + WHERE toLower(c.name) CONTAINS toLower($company) + RETURN c.name AS name + ORDER BY size(c.name) + LIMIT 1 + """, + {"company": company}, + ).single() + if result: + resolved[company] = result["name"] + logger.info("Resolved company '%s' -> '%s'", company, result["name"]) + else: + resolved[company] = company + logger.warning("Could not resolve company '%s', using as-is", company) + return resolved + + +def entity_resolution( + entity_extraction: dict, + neo4j_driver: Driver, + query_intent: str, +) -> dict: + """ + Resolve each extracted entity to its canonical form in Neo4j. + + Returns the same structure as entity_extraction but with values + replaced by their canonical graph names. Also normalises: + - year_after -> date string '>YYYY-01-01' for Cypher comparison + - year_before -> date string ' kept as floats + """ + if query_intent == "VECTOR" or not entity_extraction: + return entity_extraction + + resolved = {} + + with neo4j_driver.session() as session: + if entity_extraction.get("persons"): + resolved["persons"] = _resolve_persons( + entity_extraction["persons"], session + ) + + if entity_extraction.get("movies"): + resolved["movies"] = _resolve_movies( + entity_extraction["movies"], session + ) + + if entity_extraction.get("genres"): + resolved["genres"] = _resolve_genres( + entity_extraction["genres"], session + ) + + if entity_extraction.get("companies"): + resolved["companies"] = _resolve_companies( + entity_extraction["companies"], session + ) + + # Pass through numeric/date filters unchanged + for key in ("year_after", "year_before", "rating_above", "rating_below"): + if key in entity_extraction: + resolved[key] = entity_extraction[key] + + logger.info("Resolved entities: %s", resolved) + return resolved + + +# --------------------------------------------------------------------------- +# 4. Vector path +# --------------------------------------------------------------------------- + +def query_embedding( + user_query: str, + openai_api_key: str, + query_intent: str, +) -> list[float]: + """Embed the user query. Returns empty list for CYPHER/AGGREGATE.""" + if query_intent not in ("VECTOR", "HYBRID"): + logger.info("Skipping embedding for intent: %s", query_intent) + return [] + + client = openai.OpenAI(api_key=openai_api_key) + response = client.embeddings.create( + model=EMBEDDING_MODEL, + input=user_query, + ) + embedding = response.data[0].embedding + logger.info("Computed query embedding (%d dims)", len(embedding)) + return embedding + + +def vector_results( + query_embedding: list[float], + neo4j_driver: Driver, + query_intent: str, +) -> list[dict]: + """Run vector similarity search. Returns empty list for CYPHER/AGGREGATE.""" + if query_intent not in ("VECTOR", "HYBRID") or not query_embedding: + return [] + + cypher = """ + CALL db.index.vector.queryNodes($index_name, $top_k, $query_vector) + YIELD node, score + RETURN + node.id AS id, + node.title AS title, + node.overview AS overview, + node.release_date AS release_date, + node.vote_average AS vote_average, + score + ORDER BY score DESC + """ + with neo4j_driver.session() as session: + rows = session.run( + cypher, + { + "index_name": VECTOR_INDEX_NAME, + "top_k": TOP_K, + "query_vector": query_embedding, + }, + ).data() + + logger.info( + "Vector search: %d results (top score: %.4f)", + len(rows), + rows[0]["score"] if rows else 0.0, + ) + return rows + + +# --------------------------------------------------------------------------- +# 5. Cypher generation using resolved entities +# --------------------------------------------------------------------------- + +def _build_entity_context(resolved: dict) -> str: + """ + Build a plain-English summary of resolved entities for the Cypher + generation prompt so the LLM uses exact canonical names. + """ + if not resolved: + return "" + + lines = ["Resolved entities to use in the query (use these EXACT values):"] + + persons = resolved.get("persons", {}) + if persons: + for original, canonical in persons.items(): + lines.append(f' Person: "{canonical}"') + + movies = resolved.get("movies", {}) + if movies: + for original, canonical in movies.items(): + lines.append(f' Movie title: "{canonical}"') + + genres = resolved.get("genres", {}) + if genres: + for original, canonical in genres.items(): + lines.append(f' Genre: "{canonical}"') + + companies = resolved.get("companies", {}) + if companies: + for original, canonical in companies.items(): + lines.append(f' ProductionCompany: "{canonical}"') + + if "year_after" in resolved: + lines.append(f' Date filter: m.release_date > \'{resolved["year_after"]}-01-01\'') + if "year_before" in resolved: + lines.append(f' Date filter: m.release_date < \'{resolved["year_before"]}-12-31\'') + if "rating_above" in resolved: + lines.append(f' Rating filter: m.vote_average > {resolved["rating_above"]}') + if "rating_below" in resolved: + lines.append(f' Rating filter: m.vote_average < {resolved["rating_below"]}') + + return "\n".join(lines) + + +def _generate_cypher( + user_query: str, + entity_context: str, + client: openai.OpenAI, + hint: str = "", +) -> str: + """Generate Cypher using the schema, examples, and resolved entity context.""" + system = f"""You are an expert Neo4j Cypher query generator. + +Graph schema: +{SCHEMA_PROMPT} + +Example queries: +{CYPHER_EXAMPLES} + +{entity_context} + +Rules: +- Use ONLY the exact entity names provided above — do not paraphrase or guess +- Relationship directions: (Person)-[:DIRECTED]->(Movie), (Person)-[:ACTED_IN]->(Movie), + (Movie)-[:IN_GENRE]->(Genre), (Movie)-[:PRODUCED_BY]->(ProductionCompany) +- Use exact match {{name: 'resolved name'}} when entity is resolved, CONTAINS only as fallback +- Always alias RETURN fields with meaningful names: actor, director, movie, genre, company +- For date comparisons use STRING comparison: m.release_date > '2010-12-31' + (release_date is stored as a string, NOT a Neo4j date type) +- For aggregation ranking queries add: WITH ..., count(m) AS film_count WHERE film_count >= 3 +- For "highest rated" queries ALWAYS add WHERE m.popularity > 5 to exclude obscure low-vote films +- LIMIT 20 unless counting +- Return ONLY the Cypher query, no explanation, no markdown fences +{hint}""" + + response = client.chat.completions.create( + model="gpt-4o", + messages=[ + {"role": "system", "content": system}, + {"role": "user", "content": f"Generate a Cypher query for: {user_query}"}, + ], + temperature=0.0, + max_tokens=500, + ) + raw = response.choices[0].message.content.strip() + if raw.startswith("```"): + raw = "\n".join(raw.split("\n")[1:]) + if raw.endswith("```"): + raw = "\n".join(raw.split("\n")[:-1]) + return raw.strip() + + +def _execute_cypher(cypher: str, driver: Driver) -> list[dict]: + """Execute Cypher and return results as list of dicts.""" + try: + with driver.session() as session: + return session.run(cypher).data() + except Exception as e: + logger.warning("Cypher execution failed: %s", e) + return [] + + +def cypher_query( + user_query: str, + entity_resolution: dict, + openai_api_key: str, + query_intent: str, + neo4j_driver: Driver, +) -> str: + """ + Generate and validate a Cypher query using resolved entities. + Retries once with a relaxed hint if first attempt returns no results. + Returns the successful Cypher string or empty string. + """ + if query_intent == "VECTOR": + return "" + + client = openai.OpenAI(api_key=openai_api_key) + entity_context = _build_entity_context(entity_resolution) + + for attempt in range(MAX_RETRIES): + hint = "" + if attempt == 1: + hint = ( + "\nHINT: The previous query returned no results. " + "Double-check relationship directions. " + "Try broadening filters or using CONTAINS as a fallback for name matching." + ) + + cypher = _generate_cypher(user_query, entity_context, client, hint) + logger.info("Generated Cypher (attempt %d):\n%s", attempt + 1, cypher) + + results = _execute_cypher(cypher, neo4j_driver) + if results: + logger.info("Cypher returned %d results", len(results)) + return cypher + + logger.warning("Cypher attempt %d returned no results", attempt + 1) + + logger.error("All Cypher attempts failed for: %s", user_query) + return "" + + +def cypher_results( + cypher_query: str, + neo4j_driver: Driver, +) -> list[dict]: + """Execute the validated Cypher query and return results.""" + if not cypher_query: + return [] + results = _execute_cypher(cypher_query, neo4j_driver) + logger.info("Cypher results: %d rows", len(results)) + return results + + +# --------------------------------------------------------------------------- +# 6. Enrich vector results with graph traversal +# --------------------------------------------------------------------------- + +def _enrich_movie(movie_id: int, driver: Driver) -> dict | None: + """Pull directors, cast, genres, companies for a movie node.""" + cypher = """ + MATCH (m:Movie {id: $movie_id}) + OPTIONAL MATCH (d:Person)-[:DIRECTED]->(m) + OPTIONAL MATCH (a:Person)-[r:ACTED_IN]->(m) + WITH m, d, a, r ORDER BY r.order ASC + OPTIONAL MATCH (m)-[:IN_GENRE]->(g:Genre) + OPTIONAL MATCH (m)-[:PRODUCED_BY]->(c:ProductionCompany) + RETURN + m.title AS title, + m.overview AS overview, + m.release_date AS release_date, + m.vote_average AS vote_average, + collect(DISTINCT d.name) AS directors, + collect(DISTINCT a.name)[0..$max_cast] AS cast, + collect(DISTINCT g.name) AS genres, + collect(DISTINCT c.name) AS companies + """ + with driver.session() as session: + row = session.run(cypher, {"movie_id": movie_id, "max_cast": MAX_CAST}).single() + return dict(row) if row else None + + +# --------------------------------------------------------------------------- +# 7. Merge results +# --------------------------------------------------------------------------- + +def merged_results( + vector_results: list[dict], + cypher_results: list[dict], + neo4j_driver: Driver, + query_intent: str, +) -> list[dict]: + """Merge Cypher and vector results. Cypher results come first.""" + final = [] + + if cypher_results: + final.extend({"_source": "cypher", **row} for row in cypher_results) + + if vector_results: + seen_ids = set() + for hit in vector_results: + movie_id = hit.get("id") + if movie_id in seen_ids: + continue + seen_ids.add(movie_id) + enriched = _enrich_movie(movie_id, neo4j_driver) + if enriched: + enriched["_source"] = "vector" + enriched["_score"] = hit.get("score", 0.0) + final.append(enriched) + + logger.info( + "Merged %d results (%d cypher, %d vector)", + len(final), + len(cypher_results), + len([r for r in final if r.get("_source") == "vector"]), + ) + return final + + +# --------------------------------------------------------------------------- +# 8. Format context +# --------------------------------------------------------------------------- + +def retrieved_context(merged_results: list[dict], query_intent: str) -> str: + """ + Format merged results into plain-text context for the generation DAG. + + Enriched movie records (from vector path) are formatted with full + metadata. Raw Cypher rows are formatted as numbered plain-English + lines with field labels so the LLM can read them directly. + """ + if not merged_results: + return "No relevant information found in the knowledge graph for this query." + + FIELD_LABELS = { + "movie": "Movie", + "director": "Director", + "actor": "Actor", + "genre": "Genre", + "company": "Production company", + "film_count": "Films", + "movie_count": "Count", + "action_movie_count": "Action movies", + "avg_rating": "Avg rating", + "average_rating": "Avg rating", + "vote_average": "Rating", + "release_date": "Released", + } + + lines = [] + i = 0 + + for row in merged_results: + i += 1 + source = row.get("_source", "unknown") + + if "directors" in row: + # Enriched movie record from vector path + directors = ", ".join(row.get("directors") or []) or "Unknown" + cast = ", ".join(row.get("cast") or []) or "Unknown" + genres = ", ".join(row.get("genres") or []) or "Unknown" + companies = ", ".join(row.get("companies") or []) or "Unknown" + release = (row.get("release_date") or "")[:4] or "N/A" + rating = row.get("vote_average", "N/A") + title = row.get("title", "Unknown") + overview = row.get("overview", "") + lines.append(f"{i}. {title} ({release}) — Rating: {rating}") + lines.append(f" Directed by: {directors}") + lines.append(f" Cast: {cast}") + lines.append(f" Genres: {genres}") + lines.append(f" Produced by: {companies}") + if overview: + lines.append(f" Overview: {overview}") + lines.append("") + else: + # Raw Cypher result row + clean = {k: v for k, v in row.items() if not k.startswith("_")} + parts = [] + for k, v in clean.items(): + label = FIELD_LABELS.get(k, k.replace("_", " ").capitalize()) + if isinstance(v, float): + v = round(v, 3) + parts.append(f"{label}: {v}") + lines.append(f"{i}. " + " | ".join(parts)) + + context = "\n".join(lines) + logger.info("Formatted context: %d chars from %d results", len(context), len(merged_results)) + return context \ No newline at end of file diff --git a/examples/LLM_Workflows/neo4j_graph_rag/run.py b/examples/LLM_Workflows/neo4j_graph_rag/run.py new file mode 100644 index 000000000..ca995bd14 --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/run.py @@ -0,0 +1,242 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Entry point for the Neo4j GraphRAG example. + +Usage +----- +# Step 1 — ingest TMDB data into Neo4j +python run.py --mode ingest + +# Step 2 — compute and store embeddings on Movie nodes +python run.py --mode embed + +# Step 3 — ask questions against the populated graph +python run.py --mode query --question "Who directed Inception?" + +# Visualise any DAG without executing +python run.py --mode ingest --visualise +python run.py --mode embed --visualise +python run.py --mode query --visualise +""" + +import argparse +import logging +import os +from pathlib import Path + +from dotenv import load_dotenv +from hamilton import driver +from neo4j import GraphDatabase + +import embed_module +import generation_module +import ingest_module +import retrieval_module +from graph_schema import CONSTRAINTS + +load_dotenv() +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") +logger = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# helpers +# --------------------------------------------------------------------------- + + +def get_env(key: str) -> str: + val = os.getenv(key) + if not val: + raise EnvironmentError(f"Missing required environment variable: {key}") + return val + + +def make_neo4j_driver(): + uri = get_env("NEO4J_URI") + user = get_env("NEO4J_USERNAME") + password = get_env("NEO4J_PASSWORD") + drv = GraphDatabase.driver(uri, auth=(user, password)) + drv.verify_connectivity() + logger.info("Connected to Neo4j at %s", uri) + return drv + + +def apply_constraints(drv): + with drv.session() as session: + for constraint in CONSTRAINTS: + session.run(constraint) + logger.info("Applied %d constraints", len(CONSTRAINTS)) + + +# --------------------------------------------------------------------------- +# ingest +# --------------------------------------------------------------------------- + + +def run_ingest(visualise: bool = False): + data_dir = Path(__file__).parent / "data" + movies_path = str(data_dir / "tmdb_5000_movies.json") + credits_path = str(data_dir / "tmdb_5000_credits.json") + + for p in [movies_path, credits_path]: + if not Path(p).exists(): + raise FileNotFoundError( + f"Missing data file: {p}\n" + "Download from https://www.kaggle.com/datasets/tmdb/tmdb-movie-metadata " + "and place both JSON files in the data/ folder.\n" + "See data/README.md for conversion instructions." + ) + + drv = make_neo4j_driver() + apply_constraints(drv) + + ingest_driver = driver.Builder().with_modules(ingest_module).build() + + if visualise: + ingest_driver.display_all_functions("ingest_dag.png") + logger.info("Saved ingest DAG visualisation to ingest_dag.png") + drv.close() + return + + result = ingest_driver.execute( + ["ingestion_summary"], + inputs={ + "movies_path": movies_path, + "credits_path": credits_path, + "neo4j_driver": drv, + }, + ) + s = result["ingestion_summary"] + logger.info( + "Ingestion complete — movies: %d, genre edges: %d, " + "company edges: %d, person edges: %d", + s["movies"], s["genre_edges"], s["company_edges"], s["person_edges"], + ) + drv.close() + + +# --------------------------------------------------------------------------- +# embed +# --------------------------------------------------------------------------- + + +def run_embed(visualise: bool = False): + drv = make_neo4j_driver() + openai_api_key = get_env("OPENAI_API_KEY") + + embed_driver = driver.Builder().with_modules(embed_module).build() + + if visualise: + embed_driver.display_all_functions("embed_dag.png") + logger.info("Saved embed DAG visualisation to embed_dag.png") + drv.close() + return + + result = embed_driver.execute( + ["embedding_summary"], + inputs={ + "neo4j_driver": drv, + "openai_api_key": openai_api_key, + }, + ) + s = result["embedding_summary"] + logger.info( + "Embedding complete — %d embeddings written, index: %s, model: %s", + s["embeddings_written"], s["vector_index"], s["model"], + ) + drv.close() + + +# --------------------------------------------------------------------------- +# query +# --------------------------------------------------------------------------- + + +def run_query(question: str, visualise: bool = False): + drv = make_neo4j_driver() + openai_api_key = get_env("OPENAI_API_KEY") + + rag_driver = ( + driver.Builder() + .with_modules(retrieval_module, generation_module) + .build() + ) + + if visualise: + rag_driver.display_all_functions("rag_dag.png") + logger.info("Saved RAG DAG visualisation to rag_dag.png") + drv.close() + return + + result = rag_driver.execute( + ["answer"], + inputs={ + "user_query": question, + "neo4j_driver": drv, + "openai_api_key": openai_api_key, + }, + ) + print("\n" + "=" * 60) + print(f"Q: {question}") + print("=" * 60) + print(f"A: {result['answer']}") + print("=" * 60 + "\n") + drv.close() + + +# --------------------------------------------------------------------------- +# main +# --------------------------------------------------------------------------- + + +def main(): + parser = argparse.ArgumentParser(description="Neo4j GraphRAG — TMDB Movies") + parser.add_argument( + "--mode", + choices=["ingest", "embed", "query"], + required=True, + help=( + "ingest: load TMDB data into Neo4j | " + "embed: compute and store embeddings | " + "query: ask a question" + ), + ) + parser.add_argument( + "--question", + type=str, + default="Which movies did Christopher Nolan direct?", + help="Question to ask (only used in query mode)", + ) + parser.add_argument( + "--visualise", + action="store_true", + help="Save a PNG of the Hamilton DAG and exit without executing", + ) + args = parser.parse_args() + + if args.mode == "ingest": + run_ingest(visualise=args.visualise) + elif args.mode == "embed": + run_embed(visualise=args.visualise) + elif args.mode == "query": + run_query(question=args.question, visualise=args.visualise) + + +if __name__ == "__main__": + main() \ No newline at end of file From 4721cd457124dc87ad5253940c01d43d5dc5d70d Mon Sep 17 00:00:00 2001 From: kartikeyamandhar Date: Sun, 29 Mar 2026 22:36:50 -0700 Subject: [PATCH 02/20] Fix README image URLs with correct GitHub username --- examples/LLM_Workflows/neo4j_graph_rag/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/LLM_Workflows/neo4j_graph_rag/README.md b/examples/LLM_Workflows/neo4j_graph_rag/README.md index 69273c55d..f1c4b277a 100644 --- a/examples/LLM_Workflows/neo4j_graph_rag/README.md +++ b/examples/LLM_Workflows/neo4j_graph_rag/README.md @@ -35,7 +35,7 @@ executing the pipeline. python run.py --mode ingest --visualise ``` -![Ingestion DAG](docs/images/ingest_dag.png) +![Ingestion DAG](https://raw.githubusercontent.com/kartikeyamandhar/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/ingest_dag.png) Raw TMDB JSON flows through parsing nodes into batched Neo4j writes. Hamilton automatically parallelises the four independent branches @@ -50,7 +50,7 @@ and `raw_credits` inputs. python run.py --mode embed --visualise ``` -![Embedding DAG](docs/images/embed_dag.png) +![Embedding DAG](https://raw.githubusercontent.com/kartikeyamandhar/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/embed_dag.png) Movie texts are fetched from Neo4j, batched through the OpenAI embeddings API, written back to Movie nodes, and a cosine vector index is created. @@ -63,7 +63,7 @@ API, written back to Movie nodes, and a cosine vector index is created. python run.py --mode query --visualise ``` -![RAG DAG](docs/images/rag_dag.png) +![RAG DAG](https://raw.githubusercontent.com/kartikeyamandhar/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/rag_dag.png) The full 13-node RAG pipeline. Hamilton wires all dependencies from function signatures — no manual orchestration: From 80cb3770bbab54aefda3e053fb7fc53b72a12535 Mon Sep 17 00:00:00 2001 From: kartikeyamandhar Date: Sun, 29 Mar 2026 22:41:22 -0700 Subject: [PATCH 03/20] Fix .gitignore patterns and add DAG images --- .../LLM_Workflows/neo4j_graph_rag/.gitignore | 6 +++--- .../neo4j_graph_rag/docs/images/embed_dag.png | Bin 0 -> 44604 bytes .../neo4j_graph_rag/docs/images/ingest_dag.png | Bin 0 -> 91324 bytes .../neo4j_graph_rag/docs/images/rag_dag.png | Bin 0 -> 175661 bytes 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/docs/images/embed_dag.png create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/docs/images/ingest_dag.png create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/docs/images/rag_dag.png diff --git a/examples/LLM_Workflows/neo4j_graph_rag/.gitignore b/examples/LLM_Workflows/neo4j_graph_rag/.gitignore index 7a8422825..dd9ab9599 100644 --- a/examples/LLM_Workflows/neo4j_graph_rag/.gitignore +++ b/examples/LLM_Workflows/neo4j_graph_rag/.gitignore @@ -15,9 +15,9 @@ data/*.json data/*.csv # DAG visualisations are committed — ignore regenerated copies at root -ingest_dag.png -embed_dag.png -rag_dag.png +/ingest_dag.png +/embed_dag.png +/rag_dag.png # Neo4j *.dump diff --git a/examples/LLM_Workflows/neo4j_graph_rag/docs/images/embed_dag.png b/examples/LLM_Workflows/neo4j_graph_rag/docs/images/embed_dag.png new file mode 100644 index 0000000000000000000000000000000000000000..698bb0814380d54e6e077a2bbf160eeb1a293d32 GIT binary patch literal 44604 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%0A#R5)17Ntr7RW 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 m)Ag#n@<>f*r%W;!NES#S?0jJ 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 literal 0 HcmV?d00001 From 7bb66cd170abfda6368b004afb8a43a02504f59a Mon Sep 17 00:00:00 2001 From: Joe Marsh Rossney <17361029+jmarshrossney@users.noreply.github.com> Date: Sat, 4 Apr 2026 04:52:06 +0100 Subject: [PATCH 04/20] Fix `@resolve` decorator not calling `validate()` on returned decorators (#1524) * call decorator.validate() in resolve.resolve so that delayed evaluation of extract_fields works; add unit test * fix new failures in delayed resolve tests by defining dummy functions with valid annotations within the test body * correct probably typo in test name * add note above the 'defensive' hasattr check to explain its presence * add additional tests for resolve + extract_fields; test resolve + arbitrary decorator * add one more test that uses parameterize_sources instead of extract_fields * Apply suggestion from @skrawcz --------- Co-authored-by: Stefan Krawczyk --- hamilton/function_modifiers/delayed.py | 11 +- tests/function_modifiers/test_delayed.py | 140 ++++++++++++++++++++--- 2 files changed, 137 insertions(+), 14 deletions(-) diff --git a/hamilton/function_modifiers/delayed.py b/hamilton/function_modifiers/delayed.py index d22ef9231..2eb8725fe 100644 --- a/hamilton/function_modifiers/delayed.py +++ b/hamilton/function_modifiers/delayed.py @@ -169,7 +169,16 @@ def resolve(self, config: dict[str, Any], fn: Callable) -> NodeTransformLifecycl for key in self._optional_config: if key in config: kwargs[key] = config[key] - return self.decorate_with(**kwargs) + decorator = self.decorate_with(**kwargs) + + # NOTE: cases where `decorator` has no `validate` method should be caught by type checkers + # since `decorate_with` is typed as `Callable[..., NodeTransformLifecycle]`. The following + # check allows non-conforming functions to be used with `resolve` without immediately + # throwing an error, which may be undesirable. + if hasattr(decorator, "validate"): + decorator.validate(fn) + + return decorator class resolve_from_config(resolve): diff --git a/tests/function_modifiers/test_delayed.py b/tests/function_modifiers/test_delayed.py index 4dcf11818..b48fc92b9 100644 --- a/tests/function_modifiers/test_delayed.py +++ b/tests/function_modifiers/test_delayed.py @@ -17,6 +17,7 @@ from collections.abc import Callable +import pandas as pd import pytest from hamilton import settings @@ -24,6 +25,8 @@ ResolveAt, base, extract_columns, + extract_fields, + parameterize_sources, resolve, resolve_from_config, ) @@ -68,12 +71,17 @@ def test_extract_and_validate_params_unhappy(fn: Callable): def test_dynamic_resolves(): + # Note: we use an empty DataFrame for validation only. This test would fail at runtime + # if we actually tried to execute the DAG because there are no columns "a" or "b" to extract. + def fn() -> pd.DataFrame: + return pd.DataFrame() + decorator = resolve( when=ResolveAt.CONFIG_AVAILABLE, decorate_with=lambda cols_to_extract: extract_columns(*cols_to_extract), ) decorator_resolved = decorator.resolve( - {"cols_to_extract": ["a", "b"], **CONFIG_WITH_POWER_MODE_ENABLED}, fn=test_dynamic_resolves + {"cols_to_extract": ["a", "b"], **CONFIG_WITH_POWER_MODE_ENABLED}, fn=fn ) # This uses an internal component of extract_columns # We may want to add a little more comprehensive testing @@ -82,11 +90,15 @@ def test_dynamic_resolves(): def test_dynamic_resolve_with_configs(): + def fn() -> pd.DataFrame: + return pd.DataFrame() + decorator = resolve_from_config( decorate_with=lambda cols_to_extract: extract_columns(*cols_to_extract), ) decorator_resolved = decorator.resolve( - {"cols_to_extract": ["a", "b"], **CONFIG_WITH_POWER_MODE_ENABLED}, fn=test_dynamic_resolves + {"cols_to_extract": ["a", "b"], **CONFIG_WITH_POWER_MODE_ENABLED}, + fn=fn, ) # This uses an internal component of extract_columns # We may want to add a little more comprehensive testing @@ -94,19 +106,16 @@ def test_dynamic_resolve_with_configs(): assert decorator_resolved.columns == ("a", "b") -def test_dynamic_fails_without_power_mode_fails(): +def test_dynamic_resolve_without_power_mode_fails(): + def fn() -> pd.DataFrame: + return pd.DataFrame() + decorator = resolve( when=ResolveAt.CONFIG_AVAILABLE, decorate_with=lambda cols_to_extract: extract_columns(*cols_to_extract), ) with pytest.raises(base.InvalidDecoratorException): - decorator_resolved = decorator.resolve( - CONFIG_WITH_POWER_MODE_DISABLED, fn=test_dynamic_fails_without_power_mode_fails - ) - # This uses an internal component of extract_columns - # We may want to add a little more comprehensive testing - # But for now this will work - assert decorator_resolved.columns == ("a", "b") + decorator.resolve(CONFIG_WITH_POWER_MODE_DISABLED, fn=fn) def test_config_derivation(): @@ -123,6 +132,9 @@ def test_config_derivation(): def test_delayed_with_optional(): + def fn() -> pd.DataFrame: + return pd.DataFrame() + decorator = resolve( when=ResolveAt.CONFIG_AVAILABLE, decorate_with=lambda cols_to_extract, some_cols_you_might_want_to_extract=["c"]: ( @@ -131,7 +143,7 @@ def test_delayed_with_optional(): ) resolved = decorator.resolve( {"cols_to_extract": ["a", "b"], **CONFIG_WITH_POWER_MODE_ENABLED}, - fn=test_delayed_with_optional, + fn=fn, ) assert list(resolved.columns) == ["a", "b", "c"] resolved = decorator.resolve( @@ -140,12 +152,15 @@ def test_delayed_with_optional(): "some_cols_you_might_want_to_extract": ["d"], **CONFIG_WITH_POWER_MODE_ENABLED, }, - fn=test_delayed_with_optional, + fn=fn, ) assert list(resolved.columns) == ["a", "b", "d"] def test_delayed_without_power_mode_fails(): + def fn() -> pd.DataFrame: + return pd.DataFrame() + decorator = resolve( when=ResolveAt.CONFIG_AVAILABLE, decorate_with=lambda cols_to_extract, some_cols_you_might_want_to_extract=["c"]: ( @@ -155,5 +170,104 @@ def test_delayed_without_power_mode_fails(): with pytest.raises(base.InvalidDecoratorException): decorator.resolve( {"cols_to_extract": ["a", "b"], **CONFIG_WITH_POWER_MODE_DISABLED}, - fn=test_delayed_with_optional, + fn=fn, ) + + +def test_dynamic_resolve_with_extract_fields(): + """Test that @resolve with @extract_fields calls validate() correctly.""" + + def fn() -> dict[str, int]: + return {"a": 1, "b": 2} + + decorator = resolve( + when=ResolveAt.CONFIG_AVAILABLE, + decorate_with=lambda fields: extract_fields(fields), + ) + decorator_resolved = decorator.resolve( + {"fields": {"a": int, "b": int}, **CONFIG_WITH_POWER_MODE_ENABLED}, + fn=fn, + ) + assert hasattr(decorator_resolved, "resolved_fields") + assert decorator_resolved.resolved_fields == {"a": int, "b": int} + + +def test_resolve_with_parameterize_sources(): + """Test that @resolve with @parameterize_sources calls validate() correctly.""" + + def fn(x: int, y: int) -> int: + return x + y + + decorator = resolve( + when=ResolveAt.CONFIG_AVAILABLE, + decorate_with=lambda: parameterize_sources(result_1={"x": "source_x", "y": "source_y"}), + ) + decorator_resolved = decorator.resolve( + {**CONFIG_WITH_POWER_MODE_ENABLED}, + fn=fn, + ) + assert "result_1" in decorator_resolved.parameterization + mapping = decorator_resolved.parameterization["result_1"] + assert mapping["x"].source == "source_x" + assert mapping["y"].source == "source_y" + + +def test_resolve_from_config_with_extract_fields(): + """Test @resolve_from_config with @extract_fields calls validate() correctly.""" + + def fn() -> dict[str, int]: + return {"a": 1, "b": 2} + + decorator = resolve_from_config( + decorate_with=lambda fields: extract_fields(fields), + ) + decorator_resolved = decorator.resolve( + {"fields": {"a": int, "b": int}, **CONFIG_WITH_POWER_MODE_ENABLED}, + fn=fn, + ) + assert hasattr(decorator_resolved, "resolved_fields") + assert decorator_resolved.resolved_fields == {"a": int, "b": int} + + +def test_resolve_propagates_validate_failure(): + """Test that validate() failures are propagated through resolve.""" + + def fn() -> str: + return "not what you were expecting..." + + decorator = resolve( + when=ResolveAt.CONFIG_AVAILABLE, + decorate_with=lambda fields: extract_fields(fields), + ) + with pytest.raises(base.InvalidDecoratorException): + decorator.resolve( + {"fields": {"a": int, "b": int}, **CONFIG_WITH_POWER_MODE_ENABLED}, + fn=fn, + ) + + +def test_resolve_with_arbitrary_decorator(): + """Test behavior when decorate_with returns something that is not a NodeTransformLifecycle.""" + + # NOTE: we want to ensure we don't interfere with other decorators on functions. + + # A decorator that doesn't inherit from NodeTransformLifecycle (but still uses kwargs only) + class ArbitraryDecorator: + def __init__(self, a: int, b: int) -> None: + pass + + def __call__(self, f: Callable) -> Callable: + return f + + def fn() -> pd.DataFrame: + return pd.DataFrame() + + decorator = resolve( + when=ResolveAt.CONFIG_AVAILABLE, + decorate_with=lambda kwargs: ArbitraryDecorator(**kwargs), + ) + decorator_resolved = decorator.resolve( + {"kwargs": {"a": 1, "b": 2}, **CONFIG_WITH_POWER_MODE_ENABLED}, + fn=fn, + ) + assert isinstance(decorator_resolved, ArbitraryDecorator) From 050050ddeb44c7568028acd034fce6ccca5156e3 Mon Sep 17 00:00:00 2001 From: Stefan Krawczyk Date: Fri, 3 Apr 2026 20:53:19 -0700 Subject: [PATCH 05/20] Various build & release fixes (#1529) * Fix release helper: use --no-use-vcs flag and restore twine check - Switch from FLIT_USE_VCS=0 env var to --no-use-vcs CLI flag (flit 3.12.0 does not respect the env var) - Restore twine to prerequisites check - Restore verify_wheel_with_twine call before signing Add release tooling: verification scripts, build fixes, and docs - Add verify_apache_artifacts.py for GPG signature, checksum, and license verification - Add scripts/README.md with build, release, and voter verification instructions (uv-based) - Add .rat-excludes for Apache RAT license header checks - Add verify_ui_build.sh with Apache license header - Fix release helper: add verify_wheel_with_twine function, --dry-run flag, remove -incubating suffix from wheel (invalid per PEP 427), clean up original flit artifacts after creating incubating copies - Add tests, plugin_tests, and representative examples to flit sdist includes * Adds uv run to examples adds uv run to examples * Address PR review feedback - Fix typo: singed -> signed in release helper - Use list unpacking instead of concatenation for files_to_upload - Validate exactly 1 tarball/wheel from glob (not just non-empty) - Add release dependency group (flit, twine) to pyproject.toml - Update README to use uv sync --group release and uv sync --group test - Fix grammar and add --clean flag to uv venv in README - Add uv run prefix to verify_apache_artifacts.py epilog examples - Run ruff format on verify_apache_artifacts.py * Exclude databackend from license check in pre-commit --- .pre-commit-config.yaml | 3 +- .rat-excludes | 19 + pyproject.toml | 11 + scripts/README.md | 289 +++++++++++ scripts/apache_release_helper.py | 171 ++++--- scripts/verify_apache_artifacts.py | 769 +++++++++++++++++++++++++++++ scripts/verify_ui_build.sh | 172 +++++++ 7 files changed, 1367 insertions(+), 67 deletions(-) create mode 100644 .rat-excludes create mode 100644 scripts/README.md create mode 100755 scripts/verify_apache_artifacts.py create mode 100755 scripts/verify_ui_build.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e33449f34..cfd3b1247 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -69,7 +69,8 @@ repos: (?x) ^\.github/| ^docs/| - ^examples/ + ^examples/| + ^hamilton/experimental/databackend.py args: - --comment-style - "|#|" diff --git a/.rat-excludes b/.rat-excludes new file mode 100644 index 000000000..05b78f9dd --- /dev/null +++ b/.rat-excludes @@ -0,0 +1,19 @@ +# Requirements/data files (not source code) +.*\.txt +.*\.jsonl + +# SPDX short license template (is itself a license reference) +SHORT_LICENSE\.md + +# Data files (not source code) +.*\.json +.*\.csv +.*\.fwf +.*\.xml + +# Git and version control config +\.gitignore +\.rat-excludes + +# PKG-INFO (generated metadata) +PKG-INFO diff --git a/pyproject.toml b/pyproject.toml index f29d9543d..90b34a5b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,6 +94,10 @@ dev = [ "prek", "ruff==0.15.0", # this should match `.pre-commit-config.yaml` ] +release = [ + "flit", + "twine", +] test = [ "connectorx; python_version < '3.14'", "dask[complete]", @@ -289,6 +293,13 @@ include = [ "NOTICE", "DISCLAIMER", "scripts/**", + "tests/**", + "plugin_tests/**", + "examples/hello_world/**", + "examples/data_quality/simple/**", + "examples/reusing_functions/**", + "examples/schema/**", + "examples/pandas/materialization/**", ] exclude = [ ".git/**", diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 000000000..402cc3527 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,289 @@ + + +# Policy on source versus distribution + +Apache Hamilton is an apache-incubating project. As such, we intend to follow all Apache guidelines to +both the spirit and (when applicable) the letter. + +That said, there is occasional ambiguity. Thus we aim to clarify with a reasonable and consistently maintained +approach. The question that we found most ambiguous when determining our release process is: +1. What counts as source code, and should thus be included in the "sdist" (the source-only distribution) +2. What should be included in the build? + +Specifically, we set the following guidelines: + +| | source (to vote on) -- tar.gz | sdist -- source used to build | whl file | Reasoning | +|---|---|---|---|---| +| Build Scripts | Y | Y | N | Included in tar.gz and sdist as they are needed to reproduce the build, but not in the whl. These are only meant to be consumed by developers/pod members. | +| Library Source code | Y | Y | Y | Core library source code is included in all three distributions: tar.gz, sdist, and whl. | +| Tests (unit + plugin) | Y | Y | N | We expect users/PMC to download the source distribution, build from source, run the tests, and validate. Thus we include in the tar.gz and sdist, but not in the whl. | +| READMEs | Y | Y | Y | Standard project metadata files (README.md, LICENSE, NOTICE, DISCLAIMER) are included in all three distributions. | +| Documentation | Y | N | N | Documentation source is included in the tar.gz for voters to review, but not in the sdist or whl as it is not needed for building or using the package. | +| Representative Examples | Y | Y | N | A curated set of examples are included in tar.gz and sdist so voters can verify Hamilton works end-to-end. Not in the whl as they serve as documentation/verification only. | +| Other Examples | Y | N | N | These are included in the tar.gz for voters to review but not included in the sdist or whl. | + +# Packages + +Apache Hamilton consists of 5 independently versioned packages: + +| Package | Key | Working Directory | Description | +|---|---|---|---| +| `apache-hamilton` | `hamilton` | `.` | Core library (must be released first) | +| `apache-hamilton-sdk` | `sdk` | `ui/sdk` | Tracking SDK | +| `apache-hamilton-contrib` | `contrib` | `contrib` | Community dataflows | +| `apache-hamilton-ui` | `ui` | `ui/backend` | Web UI server | +| `apache-hamilton-lsp` | `lsp` | `dev_tools/language_server` | Language server | + +The core `apache-hamilton` package must be released first. The other four packages depend on it but not on each other. + +# Release Process + +## Environment Setup + +We recommend using [uv](https://docs.astral.sh/uv/) for Python environment management. It handles Python versions, virtual environments, and dependency installation in a single tool. + +### Prerequisites + +- Python 3.10+ +- `uv` ([install guide](https://docs.astral.sh/uv/getting-started/installation/)) +- `flit` for building +- `twine` for package validation +- GPG key configured for signing +- Node.js + npm for UI builds (only needed for the `ui` package) +- Apache RAT jar for license checking (optional, for verification) + +```bash +# Install uv (unless already installed) +curl -LsSf https://astral.sh/uv/install.sh | sh + +# Create a virtual environment with build dependencies +uv venv --python 3.11 +uv sync --group release + +# Verify GPG setup +gpg --list-secret-keys + +# IMPORTANT: set GPG_TTY so GPG can prompt for passphrase +export GPG_TTY=$(tty) +``` + +Note: all commands below use `uv run` which automatically activates the `.venv` environment. +If you prefer, you can instead `source .venv/bin/activate` and omit the `uv run` prefix. + +## Building a Release + +The main release script is `scripts/apache_release_helper.py`. It builds the sdist and wheel, signs +all artifacts with GPG, generates SHA512 checksums, uploads to Apache SVN, and generates a vote email template. + +```bash +# Release the core package (example: version 1.90.0, RC0) +uv run python scripts/apache_release_helper.py --package hamilton 1.90.0 0 your_apache_id + +# Release a downstream package (example: sdk version 0.9.0, RC0) +uv run python scripts/apache_release_helper.py --package sdk 0.9.0 0 your_apache_id +``` + +The script will: +1. Check prerequisites (`flit`, `twine`, `gpg`) +2. Validate the version in the source matches the version you specified +3. Create a git tag (`apache-hamilton-v1.90.0-incubating-RC0`) +4. Build the sdist (`.tar.gz`) and wheel (`.whl`) using `flit build --no-use-vcs` +5. Validate the wheel with `twine check` +6. Sign all artifacts with GPG and generate SHA512 checksums +7. Upload to Apache SVN dist/dev +8. Print a vote email template + +Output lands in the `dist/` directory under the package's working directory. + +### Dry Run (no SVN upload) + +To test the build and signing without uploading, you can interrupt the script after artifacts +are built (before the SVN upload step), or comment out the upload call. The artifacts will +be in the `dist/` directory for inspection. + +### After the Vote Passes + +```bash +# Push the git tag +git push origin apache-hamilton-v1.90.0-incubating-RC0 + +# Upload to PyPI (from the package's working directory) +uv run twine upload dist/apache_hamilton-1.90.0.tar.gz dist/apache_hamilton-1.90.0-py3-none-any.whl +``` + +# For Voters: Verifying a Release + +If you're voting on a release, follow these steps to verify the release candidate. + +## Complete Verification Workflow + +```bash +# Set version and RC number +export VERSION=1.90.0 +export RC=0 +export PACKAGE=apache-hamilton # or apache-hamilton-sdk, etc. + +# 1. Download all artifacts from SVN +svn export https://dist.apache.org/repos/dist/dev/incubator/hamilton/${PACKAGE}-${VERSION}-incubating-RC${RC}/ hamilton-rc${RC} +cd hamilton-rc${RC} + +# 2. Import KEYS file and verify GPG signatures +wget https://downloads.apache.org/incubator/hamilton/KEYS +gpg --import KEYS + +# Verify sdist signature +gpg --verify ${PACKAGE}-${VERSION}-incubating.tar.gz.asc ${PACKAGE}-${VERSION}-incubating.tar.gz + +# Verify wheel signature (note: underscores in wheel filenames) +WHEEL_NAME=$(echo ${PACKAGE} | tr '-' '_')-${VERSION}-py3-none-any.whl +gpg --verify ${WHEEL_NAME}.asc ${WHEEL_NAME} + +# 3. Verify SHA512 checksums +shasum -a 512 -c ${PACKAGE}-${VERSION}-incubating.tar.gz.sha512 +shasum -a 512 -c ${WHEEL_NAME}.sha512 + +# 4. Extract the source archive and build from source +tar -xzf ${PACKAGE}-${VERSION}-incubating.tar.gz +cd ${PACKAGE}-${VERSION}-incubating/ +``` + +## Build from Source with uv + +All remaining steps assume you are inside the extracted source directory +(`${PACKAGE}-${VERSION}-incubating/`) from the step above. + +```bash +# Create a fresh environment and install build tools +uv venv --python 3.11 --clean +uv sync --group release + +# Build the wheel from source +uv run flit build --no-use-vcs + +# Install the wheel you just built +uv pip install dist/apache_hamilton-${VERSION}-py3-none-any.whl +``` + +## Run Tests + +```bash +# Install test dependencies (uses the test dependency group from pyproject.toml) +uv sync --group test + +# Run core unit tests +uv run pytest tests/ -x -q + +# Run plugin tests +uv run pytest plugin_tests/ -x -q +``` + +## Run Examples + +The source archive includes representative examples to verify Hamilton works end-to-end. Each example may require additional dependencies. + +### Hello World (no extra deps) +```bash +cd examples/hello_world +uv run python my_script.py +cd ../.. +``` + +### Data Quality with Pandera +```bash +uv pip install pandera +cd examples/data_quality/simple +uv run python run.py +cd ../../.. +``` + +### Function Reuse +```bash +cd examples/reusing_functions +uv run python run.py +cd ../.. +``` + +### Schema Validation +```bash +cd examples/schema +uv run python run.py +cd ../.. +``` + +### Materialization (Pandas) +```bash +uv pip install openpyxl xlsxwriter +cd examples/pandas/materialization +uv run python run.py +cd ../../.. +``` + +## Verification Script + +For automated verification of signatures, checksums, and license compliance, use the verification script. +Run these from inside the extracted source directory (`${PACKAGE}-${VERSION}-incubating/`). + +### Prerequisites + +Download Apache RAT for license verification (into the extracted source directory): + +```bash +curl -O https://repo1.maven.org/maven2/org/apache/rat/apache-rat/0.15/apache-rat-0.15.jar +``` + +### Running Verification + +```bash +# Run from the extracted source directory (${PACKAGE}-${VERSION}-incubating/) +# Verify GPG signatures and SHA512 checksums +uv run python scripts/verify_apache_artifacts.py signatures + +# Verify license headers (requires Apache RAT) +uv run python scripts/verify_apache_artifacts.py licenses --rat-jar apache-rat-0.15.jar + +# Verify everything +uv run python scripts/verify_apache_artifacts.py all --rat-jar apache-rat-0.15.jar + +# Inspect artifact contents +uv run python scripts/verify_apache_artifacts.py list-contents dist/apache-hamilton-1.90.0-incubating.tar.gz +uv run python scripts/verify_apache_artifacts.py list-contents dist/apache_hamilton-1.90.0-py3-none-any.whl + +# Validate wheel metadata +uv run python scripts/verify_apache_artifacts.py twine-check +``` + +# Local Development + +For local wheel building/testing without signing or the full release process: + +```bash +uv venv --python 3.11 +uv sync --group release + +# Build both sdist and wheel +uv run flit build --no-use-vcs + +# Or just the wheel +uv run flit build --no-use-vcs --format wheel + +# Install and test locally +uv pip install dist/apache_hamilton-*.whl +uv run python -c "import hamilton; print(hamilton.version.VERSION)" +``` diff --git a/scripts/apache_release_helper.py b/scripts/apache_release_helper.py index 8f3705c21..08ea342dc 100644 --- a/scripts/apache_release_helper.py +++ b/scripts/apache_release_helper.py @@ -96,7 +96,7 @@ def get_version_from_file(package_config: dict) -> str: def check_prerequisites(): """Checks for necessary command-line tools and Python modules.""" print("Checking for required tools...") - required_tools = ["git", "gpg", "svn"] + required_tools = ["git", "gpg", "svn", "twine"] for tool in required_tools: if shutil.which(tool) is None: print(f"Error: '{tool}' not found. Please install it and ensure it's in your PATH.") @@ -161,6 +161,26 @@ def update_version(package_config: dict, version, rc_num): return False +def verify_wheel_with_twine(wheel_path: str) -> bool: + """Validates wheel metadata using twine check.""" + print(f"Validating wheel with twine: {wheel_path}") + try: + result = subprocess.run( + ["twine", "check", wheel_path], + capture_output=True, + text=True, + ) + print(result.stdout) + if result.returncode != 0: + print(f"twine check failed:\n{result.stderr}") + return False + print("Wheel passed twine validation.") + return True + except Exception as e: + print(f"Error running twine check: {e}") + return False + + def sign_artifacts(archive_name: str) -> list[str] | None: """Creates signed files for the designated artifact.""" files = [] @@ -302,15 +322,13 @@ def create_release_artifacts(package_config: dict, version) -> list[str]: # Use flit build to create the source distribution. try: - env = os.environ.copy() - env["FLIT_USE_VCS"] = "0" subprocess.run( [ "flit", "build", + "--no-use-vcs", ], check=True, - env=env, ) print("Source distribution created successfully.") except subprocess.CalledProcessError as e: @@ -323,45 +341,46 @@ def create_release_artifacts(package_config: dict, version) -> list[str]: expected_tar_ball = f"dist/{package_file_name}-{version.lower()}.tar.gz" tarball_path = glob.glob(expected_tar_ball) - if not tarball_path: + if len(tarball_path) != 1: print( - f"Error: Could not find {expected_tar_ball} the generated source tarball in the 'dist' directory." + f"Error: Expected exactly 1 tarball matching {expected_tar_ball}, " + f"found {len(tarball_path)}." ) if os.path.exists("dist"): print("Contents of 'dist' directory:") for item in os.listdir("dist"): print(f"- {item}") - else: - print("'dist' directory not found.") - raise ValueError("Could not find the generated source tarball in the 'dist' directory.") + raise ValueError(f"Could not find the generated source tarball: {expected_tar_ball}") + tarball_file = tarball_path[0] # Copy the tarball to be {package-name}-{version}-incubating-src.tar.gz # Use -src suffix to distinguish source distribution from wheel (convenience package) new_tar_ball = f"dist/{package_name}-{version.lower()}-incubating-src.tar.gz" - _modify_tarball_for_apache_release(tarball_path[0], new_tar_ball, package_name) + _modify_tarball_for_apache_release(tarball_file, new_tar_ball, package_name) + # Remove original flit tarball (only keep the incubating copy) + os.remove(tarball_file) archive_name = new_tar_ball print(f"Found source tarball: {archive_name}") - new_tar_ball_singed = sign_artifacts(archive_name) - if new_tar_ball_singed is None: + new_tar_ball_signed = sign_artifacts(archive_name) + if new_tar_ball_signed is None: raise ValueError("Could not sign the main release artifacts.") - # Create wheel release artifacts + # Wheel keeps its original PEP 427 filename (no -incubating suffix) expected_wheel = f"dist/{package_file_name}-{version.lower()}-py3-none-any.whl" wheel_path = glob.glob(expected_wheel) + if len(wheel_path) != 1: + raise ValueError( + f"Expected exactly 1 wheel matching {expected_wheel}, found {len(wheel_path)}." + ) + wheel_file = wheel_path[0] - # Create incubator wheel release artifacts with -incubating suffix - expected_incubator_wheel = ( - f"dist/{package_name}-{version.lower()}-incubating-py3-none-any.whl" - ) - shutil.copy(wheel_path[0], expected_incubator_wheel) - incubator_wheel_signed_files = sign_artifacts(expected_incubator_wheel) - - files_to_upload = ( - [new_tar_ball] - + new_tar_ball_singed - + [expected_incubator_wheel] - + incubator_wheel_signed_files - ) + # Verify wheel with twine before signing + if not verify_wheel_with_twine(wheel_file): + raise ValueError("Wheel failed twine validation.") + + wheel_signed_files = sign_artifacts(wheel_file) + + files_to_upload = [new_tar_ball, *new_tar_ball_signed, wheel_file, *wheel_signed_files] return files_to_upload finally: @@ -521,6 +540,11 @@ def main(): parser.add_argument("version", help="The new release version (e.g., '1.0.0').") parser.add_argument("rc_num", help="The release candidate number (e.g., '0' for RC0).") parser.add_argument("apache_id", help="Your apache user ID.") + parser.add_argument( + "--dry-run", + action="store_true", + help="Build and sign artifacts but skip git tagging and SVN upload.", + ) args = parser.parse_args() package_key = args.package @@ -547,24 +571,29 @@ def main(): # Create git tag (from repo root) tag_name = f"{package_name}-v{version}-incubating-RC{rc_num}" - print(f"\nChecking for git tag '{tag_name}'...") - try: - # Check if the tag already exists - existing_tag = subprocess.check_output(["git", "tag", "-l", tag_name]).decode().strip() - if existing_tag == tag_name: - print(f"Git tag '{tag_name}' already exists.") - response = input("Do you want to continue without creating a new tag? (y/n): ").lower() - if response != "y": - print("Aborting.") - sys.exit(1) - else: - # Tag does not exist, create it - print(f"Creating git tag '{tag_name}'...") - subprocess.run(["git", "tag", tag_name], check=True) - print(f"Git tag {tag_name} created.") - except subprocess.CalledProcessError as e: - print(f"Error checking or creating Git tag: {e}") - sys.exit(1) + if args.dry_run: + print(f"\n[dry-run] Skipping git tag creation: {tag_name}") + else: + print(f"\nChecking for git tag '{tag_name}'...") + try: + # Check if the tag already exists + existing_tag = subprocess.check_output(["git", "tag", "-l", tag_name]).decode().strip() + if existing_tag == tag_name: + print(f"Git tag '{tag_name}' already exists.") + response = input( + "Do you want to continue without creating a new tag? (y/n): " + ).lower() + if response != "y": + print("Aborting.") + sys.exit(1) + else: + # Tag does not exist, create it + print(f"Creating git tag '{tag_name}'...") + subprocess.run(["git", "tag", tag_name], check=True) + print(f"Git tag {tag_name} created.") + except subprocess.CalledProcessError as e: + print(f"Error checking or creating Git tag: {e}") + sys.exit(1) # Create artifacts print(f"\n{'=' * 80}") @@ -574,29 +603,39 @@ def main(): if not files_to_upload: sys.exit(1) - # Upload artifacts - print(f"\n{'=' * 80}") - print(" Uploading to Apache SVN") - print(f"{'=' * 80}\n") - # NOTE: You MUST have your SVN client configured to use your Apache ID and have permissions. - svn_url = svn_upload(package_name, version, rc_num, files_to_upload, apache_id) - if not svn_url: - sys.exit(1) - - # Generate email - print(f"\n{'=' * 80}") - print(" Vote Email Template") - print(f"{'=' * 80}\n") - generate_email_template(package_name, version, rc_num, svn_url) + if args.dry_run: + # Dry run: skip SVN upload, show summary + print(f"\n{'=' * 80}") + print(" [dry-run] Skipping SVN upload") + print(f"{'=' * 80}\n") + print("Artifacts built successfully:") + for f in files_to_upload: + print(f" {f}") + print("\nTo do a real release, re-run without --dry-run.") + else: + # Upload artifacts + print(f"\n{'=' * 80}") + print(" Uploading to Apache SVN") + print(f"{'=' * 80}\n") + # NOTE: You MUST have your SVN client configured to use your Apache ID and have permissions. + svn_url = svn_upload(package_name, version, rc_num, files_to_upload, apache_id) + if not svn_url: + sys.exit(1) - print("\n" + "=" * 80) - print(" Process Complete!") - print("=" * 80) - print("\nNext steps:") - print(f"1. Push the git tag: git push origin {tag_name}") - print("2. Copy the email template above and send to dev@hamilton.apache.org") - print("3. Wait for votes (minimum 72 hours)") - print("\n") + # Generate email + print(f"\n{'=' * 80}") + print(" Vote Email Template") + print(f"{'=' * 80}\n") + generate_email_template(package_name, version, rc_num, svn_url) + + print("\n" + "=" * 80) + print(" Process Complete!") + print("=" * 80) + print("\nNext steps:") + print(f"1. Push the git tag: git push origin {tag_name}") + print("2. Copy the email template above and send to dev@hamilton.apache.org") + print("3. Wait for votes (minimum 72 hours)") + print("\n") if __name__ == "__main__": diff --git a/scripts/verify_apache_artifacts.py b/scripts/verify_apache_artifacts.py new file mode 100755 index 000000000..63da3a6f0 --- /dev/null +++ b/scripts/verify_apache_artifacts.py @@ -0,0 +1,769 @@ +#!/usr/bin/env python3 +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +""" +Apache Artifacts Verification Script + +Comprehensive verification tool for Apache release artifacts. +Checks signatures, checksums, licenses, and archive integrity. + +Usage: + # List contents of an artifact + uv run python scripts/verify_apache_artifacts.py list-contents dist/apache-hamilton-0.41.0-incubating-src.tar.gz + + # Verify signatures and checksums + uv run python scripts/verify_apache_artifacts.py signatures + + # Verify licenses with Apache RAT + uv run python scripts/verify_apache_artifacts.py licenses --rat-jar path/to/apache-rat.jar + + # Verify everything + uv run python scripts/verify_apache_artifacts.py all --rat-jar path/to/apache-rat.jar + + # Specify custom artifacts directory + uv run python scripts/verify_apache_artifacts.py signatures --artifacts-dir /path/to/dist +""" + +import argparse +import glob +import hashlib +import os +import shutil +import subprocess +import sys +import tarfile +import tempfile +import xml.etree.ElementTree as ET +import zipfile + +# Configuration +PROJECT_SHORT_NAME = "hamilton" + + +def _fail(message: str) -> None: + """Print error message and exit.""" + print(f"\n❌ {message}") + sys.exit(1) + + +def _print_section(title: str) -> None: + """Print formatted section header.""" + print("\n" + "=" * 80) + print(f" {title}") + print("=" * 80 + "\n") + + +# ============================================================================ +# Signature and Checksum Verification +# ============================================================================ + + +def _verify_artifact_signature(artifact_path: str, signature_path: str) -> bool: + """Verify GPG signature of artifact.""" + print(f" Verifying GPG signature: {os.path.basename(signature_path)}") + + if not os.path.exists(signature_path): + print(" ✗ Signature file not found") + return False + + try: + result = subprocess.run( + ["gpg", "--verify", signature_path, artifact_path], + capture_output=True, + check=False, + ) + if result.returncode == 0: + print(" ✓ GPG signature is valid") + return True + else: + print(" ✗ GPG signature verification failed") + if result.stderr: + print(f" Error: {result.stderr.decode()}") + return False + except subprocess.CalledProcessError: + print(" ✗ Error running GPG") + return False + + +def _verify_artifact_checksum(artifact_path: str, checksum_path: str) -> bool: + """Verify SHA512 checksum of artifact.""" + print(f" Verifying SHA512 checksum: {os.path.basename(checksum_path)}") + + if not os.path.exists(checksum_path): + print(" ✗ Checksum file not found") + return False + + # Read expected checksum + with open(checksum_path, "r", encoding="utf-8") as f: + expected_checksum = f.read().strip().split()[0] + + # Calculate actual checksum + sha512_hash = hashlib.sha512() + with open(artifact_path, "rb") as f: + while chunk := f.read(65536): + sha512_hash.update(chunk) + + actual_checksum = sha512_hash.hexdigest() + + if actual_checksum == expected_checksum: + print(" ✓ SHA512 checksum is valid") + return True + else: + print(" ✗ SHA512 checksum mismatch!") + print(f" Expected: {expected_checksum}") + print(f" Actual: {actual_checksum}") + return False + + +def _verify_tar_gz_readable(artifact_path: str) -> bool: + """Verify tar.gz archive can be read and contains files.""" + print(f" Checking archive readability: {os.path.basename(artifact_path)}") + + try: + with tarfile.open(artifact_path, "r:gz") as tar: + members = tar.getmembers() + + if len(members) == 0: + print(" ✗ Archive is empty (no files)") + return False + + print(f" ✓ Archive is readable and contains {len(members)} files") + return True + except tarfile.TarError as e: + print(f" ✗ Archive is corrupted or unreadable: {e}") + return False + except Exception as e: + print(f" ✗ Error reading archive: {e}") + return False + + +def _verify_wheel_readable(wheel_path: str) -> bool: + """Verify wheel can be read and contains expected structure.""" + print(f" Checking wheel readability: {os.path.basename(wheel_path)}") + + try: + with zipfile.ZipFile(wheel_path, "r") as whl: + file_list = whl.namelist() + + if len(file_list) == 0: + print(" ✗ Wheel is empty (no files)") + return False + + # Check for metadata + metadata_files = [f for f in file_list if "METADATA" in f or "WHEEL" in f] + if not metadata_files: + print(" ✗ Wheel missing required metadata files") + return False + + print(f" ✓ Wheel is readable and contains {len(file_list)} files") + return True + except zipfile.BadZipFile: + print(" ✗ Wheel is corrupted or not a valid ZIP file") + return False + except Exception as e: + print(f" ✗ Error reading wheel: {e}") + return False + + +def _verify_artifact_exists(artifact_path: str, min_size: int = 1000) -> bool: + """Verify artifact exists and has reasonable size.""" + if not os.path.exists(artifact_path): + print(f" ✗ Artifact not found: {os.path.basename(artifact_path)}") + return False + + file_size = os.path.getsize(artifact_path) + if file_size < min_size: + print( + f" ✗ Artifact is suspiciously small ({file_size} bytes): {os.path.basename(artifact_path)}" + ) + return False + + print(f" ✓ Artifact exists: {os.path.basename(artifact_path)} ({file_size:,} bytes)") + return True + + +def verify_signatures(artifacts_dir: str) -> bool: + """Verify all signatures and checksums in artifacts directory.""" + _print_section("Verifying Signatures and Checksums") + + if not os.path.exists(artifacts_dir): + _fail(f"Artifacts directory not found: {artifacts_dir}") + + # Find all artifacts (exclude .asc and .sha512 files) + all_files = [ + f for f in os.listdir(artifacts_dir) if os.path.isfile(os.path.join(artifacts_dir, f)) + ] + artifacts = [f for f in all_files if not f.endswith((".asc", ".sha512"))] + + if not artifacts: + print(f"⚠️ No artifacts found in {artifacts_dir}") + return False + + print(f"Found {len(artifacts)} artifact(s) to verify:\n") + + all_valid = True + for artifact_name in artifacts: + artifact_path = os.path.join(artifacts_dir, artifact_name) + + print(f"Verifying: {artifact_name}") + print("-" * 80) + + # Check existence and size + if not _verify_artifact_exists(artifact_path): + all_valid = False + continue + + # Verify signature + signature_path = f"{artifact_path}.asc" + if not _verify_artifact_signature(artifact_path, signature_path): + all_valid = False + + # Verify checksum + checksum_path = f"{artifact_path}.sha512" + if not _verify_artifact_checksum(artifact_path, checksum_path): + all_valid = False + + # Verify archive/wheel structure + if artifact_name.endswith(".tar.gz"): + if not _verify_tar_gz_readable(artifact_path): + all_valid = False + elif artifact_name.endswith(".whl"): + if not _verify_wheel_readable(artifact_path): + all_valid = False + + print() + + return all_valid + + +# ============================================================================ +# License Verification (Apache RAT) +# ============================================================================ + + +def _check_licenses_with_rat( + artifact_path: str, + rat_jar_path: str, + report_name: str, + report_only: bool = False, +) -> bool: + """Run Apache RAT license checker on artifact.""" + print(f"\nRunning Apache RAT on: {os.path.basename(artifact_path)}") + print("-" * 80) + + # Create reports directory + report_dir = "dist" + os.makedirs(report_dir, exist_ok=True) + + rat_report_xml = os.path.join(report_dir, f"rat-report-{report_name}.xml") + rat_report_txt = os.path.join(report_dir, f"rat-report-{report_name}.txt") + + # Extract archive to temp directory + with tempfile.TemporaryDirectory() as temp_dir: + extract_dir = os.path.join(temp_dir, "extracted") + os.makedirs(extract_dir) + + print(" Extracting archive...") + try: + with tarfile.open(artifact_path, "r:gz") as tar: + # Use data filter for Python 3.12+ to avoid deprecation warning + tar.extractall(extract_dir, filter="data") + print(" ✓ Extracted to temp directory") + except Exception as e: + print(f" ✗ Error extracting archive: {e}") + return False + + # Locate .rat-excludes file + rat_excludes = ".rat-excludes" + if not os.path.exists(rat_excludes): + print(f" ⚠️ Warning: {rat_excludes} not found, running without excludes") + rat_excludes = None + + # Run RAT with XML output + print(" Running Apache RAT (XML format for parsing)...") + rat_cmd_xml = [ + "java", + "-jar", + rat_jar_path, + "-x", # XML output + "-d", + extract_dir, + ] + if rat_excludes: + rat_cmd_xml.extend(["-E", rat_excludes]) + + try: + with open(rat_report_xml, "w", encoding="utf-8") as report_file: + result = subprocess.run( + rat_cmd_xml, + stdout=report_file, + stderr=subprocess.PIPE, + text=True, + check=False, + ) + + if result.returncode != 0: + print(f" ⚠️ RAT exited with code {result.returncode}") + + print(f" ✓ RAT XML report: {rat_report_xml}") + except Exception as e: + print(f" ✗ Error running RAT (XML): {e}") + return False + + # Run RAT with plain text output + print(" Running Apache RAT (text format for review)...") + rat_cmd_txt = [ + "java", + "-jar", + rat_jar_path, + "-d", + extract_dir, + ] + if rat_excludes: + rat_cmd_txt.extend(["-E", rat_excludes]) + + try: + with open(rat_report_txt, "w", encoding="utf-8") as report_file: + subprocess.run( + rat_cmd_txt, + stdout=report_file, + stderr=subprocess.PIPE, + text=True, + check=False, + ) + print(f" ✓ RAT text report: {rat_report_txt}") + except Exception as e: + print(f" ⚠️ Warning: Could not generate text report: {e}") + + # Parse XML report + print(" Parsing RAT report...") + try: + tree = ET.parse(rat_report_xml) + root = tree.getroot() + + # Find license issues + unapproved_licenses = [] + unknown_licenses = [] + + for resource in root.findall(".//resource"): + name = resource.get("name", "unknown") + + # Get license approval and family from child elements + license_approval_elem = resource.find("license-approval") + license_family_elem = resource.find("license-family") + + license_approval = ( + license_approval_elem.get("name", "true") + if license_approval_elem is not None + else "true" + ) + license_family = ( + license_family_elem.get("name", "") if license_family_elem is not None else "" + ) + + if license_approval == "false" or license_family == "Unknown license": + if license_family == "Unknown license" or not license_family: + unknown_licenses.append(name) + else: + unapproved_licenses.append(name) + + # Report findings + total_files = len(root.findall(".//resource")) + issues_count = len(unapproved_licenses) + len(unknown_licenses) + + print(f" ✓ Scanned {total_files} files") + print(f" ✓ Found {issues_count} files with license issues") + + if issues_count > 0: + print("\n ⚠️ License Issues Found:") + + if unknown_licenses: + print(f"\n Unknown/Missing Licenses ({len(unknown_licenses)} files):") + for file in unknown_licenses[:10]: + print(f" - {file}") + if len(unknown_licenses) > 10: + print(f" ... and {len(unknown_licenses) - 10} more") + + if unapproved_licenses: + print(f"\n Unapproved Licenses ({len(unapproved_licenses)} files):") + for file in unapproved_licenses[:10]: + print(f" - {file}") + if len(unapproved_licenses) > 10: + print(f" ... and {len(unapproved_licenses) - 10} more") + + print("\n 📄 Reports saved:") + print(f" - {rat_report_xml} (structured)") + print(f" - {rat_report_txt} (human-readable)") + + if report_only: + print("\n ℹ️ Report-only mode: continuing despite license issues") + return True + else: + print("\n ❌ License check failed!") + return False + else: + print(" ✅ All files have approved licenses") + print("\n 📄 Reports saved:") + print(f" - {rat_report_xml} (structured)") + print(f" - {rat_report_txt} (human-readable)") + return True + + except Exception as e: + print(f" ✗ Error parsing RAT report: {e}") + if report_only: + print(" ℹ️ Report-only mode: continuing despite parse error") + return True + return False + + +def verify_licenses(artifacts_dir: str, rat_jar_path: str, report_only: bool = False) -> bool: + """Verify licenses in all tar.gz artifacts using Apache RAT.""" + _print_section("Verifying Licenses with Apache RAT") + + if not os.path.exists(artifacts_dir): + _fail(f"Artifacts directory not found: {artifacts_dir}") + + if not rat_jar_path or not os.path.exists(rat_jar_path): + _fail( + f"Apache RAT JAR not found: {rat_jar_path}\nDownload from: https://creadur.apache.org/rat/download_rat.cgi" + ) + + # Check for java + if shutil.which("java") is None: + _fail("Java not found. Required for Apache RAT.") + + # Find all tar.gz artifacts (not wheels) + all_files = [ + f for f in os.listdir(artifacts_dir) if os.path.isfile(os.path.join(artifacts_dir, f)) + ] + tar_artifacts = [f for f in all_files if f.endswith(".tar.gz")] + + if not tar_artifacts: + print(f"⚠️ No tar.gz artifacts found in {artifacts_dir}") + return False + + print(f"Found {len(tar_artifacts)} tar.gz artifact(s) to check:\n") + + all_valid = True + for artifact_name in tar_artifacts: + artifact_path = os.path.join(artifacts_dir, artifact_name) + + # Generate report name from artifact name + report_name = artifact_name.replace(".tar.gz", "").replace(".", "-") + + if not _check_licenses_with_rat(artifact_path, rat_jar_path, report_name, report_only): + all_valid = False + + return all_valid + + +# ============================================================================ +# List Contents +# ============================================================================ + + +def _list_tar_gz_contents(artifact_path: str) -> None: + """List contents of a tar.gz archive.""" + print(f"\nContents of: {os.path.basename(artifact_path)}") + print("=" * 80) + + try: + with tarfile.open(artifact_path, "r:gz") as tar: + members = tar.getmembers() + + print(f"Total files: {len(members)}\n") + + # Group by type + files = [m for m in members if m.isfile()] + dirs = [m for m in members if m.isdir()] + symlinks = [m for m in members if m.issym() or m.islnk()] + + print(f"Files: {len(files)}, Directories: {len(dirs)}, Symlinks: {len(symlinks)}\n") + + # Show all files + print("Files:\n") + + for member in members: + size = f"{member.size:>12,}" if member.isfile() else " " + prefix = " " + if member.issym() or member.islnk(): + prefix = "→ " + if member.linkname: + print(f"{prefix}{member.name} -> {member.linkname}") + continue + print(f"{prefix}{member.name:<70} {size}") + + except Exception as e: + print(f"Error reading archive: {e}") + + +def _list_wheel_contents(wheel_path: str) -> None: + """List contents of a wheel file.""" + print(f"\nContents of: {os.path.basename(wheel_path)}") + print("=" * 80) + + try: + with zipfile.ZipFile(wheel_path, "r") as whl: + file_list = whl.namelist() + + print(f"Total files: {len(file_list)}\n") + + # Group by directory + top_level_dirs = {} + for file in file_list: + top_dir = file.split("/")[0] + top_level_dirs[top_dir] = top_level_dirs.get(top_dir, 0) + 1 + + print("Top-level structure:") + for dir_name, count in sorted(top_level_dirs.items()): + print(f" {dir_name:<50} ({count} files)") + + # Show all files + print("\nFiles:\n") + + for filename in sorted(file_list): + info = whl.getinfo(filename) + size = f"{info.file_size:>12,}" if not filename.endswith("/") else " " + print(f" {filename:<70} {size}") + + except Exception as e: + print(f"Error reading wheel: {e}") + + +def list_contents(artifact_path: str) -> None: + """List contents of a specific artifact.""" + _print_section("Listing Artifact Contents") + + if not os.path.exists(artifact_path): + _fail(f"Artifact not found: {artifact_path}") + + if artifact_path.endswith(".tar.gz"): + _list_tar_gz_contents(artifact_path) + elif artifact_path.endswith(".whl"): + _list_wheel_contents(artifact_path) + else: + _fail(f"Unsupported file type: {artifact_path}\nSupported: .tar.gz, .whl") + + +# ============================================================================ +# Command Handlers +# ============================================================================ + + +def cmd_signatures(args) -> bool: + """Verify signatures and checksums.""" + return verify_signatures(args.artifacts_dir) + + +def cmd_licenses(args) -> bool: + """Verify licenses with Apache RAT.""" + if not args.rat_jar: + _fail("--rat-jar is required for license verification") + + return verify_licenses(args.artifacts_dir, args.rat_jar, args.report_only) + + +def cmd_all(args) -> bool: + """Verify everything: signatures, checksums, and licenses.""" + _print_section("Complete Apache Artifacts Verification") + + # Step 1: Verify signatures + print("\n[1/2] Verifying signatures and checksums...") + signatures_ok = verify_signatures(args.artifacts_dir) + + # Step 2: Verify licenses + if args.rat_jar: + print("\n[2/2] Verifying licenses with Apache RAT...") + licenses_ok = verify_licenses(args.artifacts_dir, args.rat_jar, args.report_only) + else: + print("\n[2/2] Skipping license verification (no --rat-jar provided)") + licenses_ok = True + + # Summary + _print_section("Verification Summary") + + print("Results:") + print(f" Signatures & Checksums: {'✅ PASS' if signatures_ok else '❌ FAIL'}") + print( + f" License Compliance: {'✅ PASS' if licenses_ok else '❌ FAIL' if args.rat_jar else '⊘ SKIPPED'}" + ) + + return signatures_ok and licenses_ok + + +def cmd_list_contents(args) -> None: + """List contents of a specific artifact.""" + list_contents(args.artifact) + + +def cmd_twine_check(args) -> bool: + """Verify wheel metadata with twine.""" + _print_section("Verifying Wheel Metadata with Twine") + + wheel_pattern = f"{args.artifacts_dir}/apache_hamilton-*.whl" + wheel_files = glob.glob(wheel_pattern) + + if not wheel_files: + print(f"❌ No wheel found matching: {wheel_pattern}") + return False + + for wheel_path in wheel_files: + print(f"\nChecking {os.path.basename(wheel_path)}...") + try: + subprocess.run( + ["twine", "check", wheel_path], + check=True, + capture_output=True, + text=True, + ) + print(f" ✓ {os.path.basename(wheel_path)} metadata is valid") + except subprocess.CalledProcessError as e: + print(f" ✗ Twine check failed: {e.stderr}") + return False + + print("\n✅ All wheels passed twine validation") + return True + + +# ============================================================================ +# CLI Entry Point +# ============================================================================ + + +def main(): + """Main entry point.""" + parser = argparse.ArgumentParser( + description="Apache Artifacts Verification Tool", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # List contents of a specific artifact + uv run python scripts/verify_apache_artifacts.py list-contents dist/apache-hamilton-0.41.0-incubating-src.tar.gz + uv run python scripts/verify_apache_artifacts.py list-contents dist/apache_hamilton-0.41.0-py3-none-any.whl + + # Verify signatures and checksums only + uv run python scripts/verify_apache_artifacts.py signatures + + # Verify licenses with Apache RAT + uv run python scripts/verify_apache_artifacts.py licenses --rat-jar /path/to/apache-rat.jar + + # Verify everything + uv run python scripts/verify_apache_artifacts.py all --rat-jar /path/to/apache-rat.jar + + # Report-only mode (don't fail on license issues) + uv run python scripts/verify_apache_artifacts.py licenses --rat-jar /path/to/apache-rat.jar --report-only + + # Custom artifacts directory + uv run python scripts/verify_apache_artifacts.py all --artifacts-dir /path/to/artifacts --rat-jar /path/to/rat.jar + """, + ) + + subparsers = parser.add_subparsers(dest="command", required=True) + + # list-contents subcommand + list_parser = subparsers.add_parser( + "list-contents", help="List contents of a specific artifact" + ) + list_parser.add_argument("artifact", help="Path to artifact file (.tar.gz or .whl)") + + # signatures subcommand + sig_parser = subparsers.add_parser( + "signatures", help="Verify GPG signatures and SHA512 checksums" + ) + sig_parser.add_argument( + "--artifacts-dir", + default="dist", + help="Directory containing artifacts (default: dist)", + ) + + # licenses subcommand + lic_parser = subparsers.add_parser("licenses", help="Verify licenses with Apache RAT") + lic_parser.add_argument( + "--artifacts-dir", + default="dist", + help="Directory containing artifacts (default: dist)", + ) + lic_parser.add_argument("--rat-jar", required=True, help="Path to Apache RAT JAR file") + lic_parser.add_argument( + "--report-only", + action="store_true", + help="Generate report but don't fail on issues", + ) + + # all subcommand + all_parser = subparsers.add_parser("all", help="Verify everything (signatures + licenses)") + all_parser.add_argument( + "--artifacts-dir", + default="dist", + help="Directory containing artifacts (default: dist)", + ) + all_parser.add_argument( + "--rat-jar", help="Path to Apache RAT JAR file (optional for signatures-only)" + ) + all_parser.add_argument( + "--report-only", + action="store_true", + help="Generate report but don't fail on license issues", + ) + + # twine-check subcommand + twine_parser = subparsers.add_parser("twine-check", help="Verify wheel metadata with twine") + twine_parser.add_argument( + "--artifacts-dir", + default="dist", + help="Directory containing artifacts (default: dist)", + ) + + args = parser.parse_args() + + # Dispatch to command handler + success = False + try: + if args.command == "list-contents": + cmd_list_contents(args) + sys.exit(0) + elif args.command == "signatures": + success = cmd_signatures(args) + elif args.command == "licenses": + success = cmd_licenses(args) + elif args.command == "all": + success = cmd_all(args) + elif args.command == "twine-check": + success = cmd_twine_check(args) + else: + _fail(f"Unknown command: {args.command}") + except KeyboardInterrupt: + print("\n\n⚠️ Interrupted by user") + sys.exit(130) + except Exception as e: + print(f"\n❌ Unexpected error: {e}") + import traceback + + traceback.print_exc() + sys.exit(1) + + if success: + print("\n✅ Verification completed successfully!") + sys.exit(0) + else: + print("\n❌ Verification failed.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/scripts/verify_ui_build.sh b/scripts/verify_ui_build.sh new file mode 100755 index 000000000..e20fc38c6 --- /dev/null +++ b/scripts/verify_ui_build.sh @@ -0,0 +1,172 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Verification script for Hamilton UI build and tracking + +set -e # Exit on error + +echo "============================================" +echo "Hamilton UI Build & Tracking Verification" +echo "============================================" +echo "" + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +print_step() { + echo -e "${YELLOW}>>> $1${NC}" +} + +print_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +print_error() { + echo -e "${RED}❌ $1${NC}" +} + +# Get script directory and navigate to repo root +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$REPO_ROOT" + +print_step "Step 1: Building UI frontend..." +echo "Running full build (npm install + npm build with Vite)..." +hamilton-admin-build-ui +print_success "Frontend built successfully" + +print_step "Step 2: Verifying build output..." +cd "$REPO_ROOT" +if [ -f "ui/backend/server/build/index.html" ]; then + print_success "index.html exists" +else + print_error "index.html not found at $REPO_ROOT/ui/backend/server/build/" + exit 1 +fi + +# Vite outputs to assets/, CRA outputs to static/ +if [ -d "ui/backend/server/build/assets" ] || [ -d "ui/backend/server/build/static" ]; then + if [ -d "ui/backend/server/build/assets" ]; then + print_success "assets/ directory exists (Vite build)" + else + print_success "static/ directory exists (CRA build)" + fi +else + print_error "assets/ or static/ directory not found" + exit 1 +fi + +print_step "Step 3: Building Python package..." +cd "$REPO_ROOT/ui/backend" +python -m build --wheel +print_success "Package built successfully" + +print_step "Step 4: Verifying package contents..." +if ls dist/*.whl 1> /dev/null 2>&1; then + WHEEL_FILE=$(ls dist/*.whl | tail -1) + print_success "Wheel created: $(basename $WHEEL_FILE)" + + # Check if wheel contains build assets + if unzip -l "$WHEEL_FILE" | grep -q "hamilton_ui/build/index.html"; then + print_success "Wheel contains frontend assets" + else + print_error "Wheel missing frontend assets" + exit 1 + fi +else + print_error "No wheel file found" + exit 1 +fi + +print_step "Step 5: Running build verification tests..." +cd "$REPO_ROOT/ui/backend" +if pytest tests/test_build.py -v --tb=short; then + print_success "All tests passed" +else + print_error "Tests failed" + exit 1 +fi + +print_step "Step 6: Creating test tracking script..." +cd "$REPO_ROOT" +cat > test_tracking.py << 'EOF' +from hamilton import driver +import pandas as pd +import sys + +print("Creating simple Hamilton DAG...") + +# Define some simple functions +def data_source() -> pd.DataFrame: + """Sample data""" + return pd.DataFrame({ + 'a': [1, 2, 3, 4], + 'b': [5, 6, 7, 8] + }) + +def sum_columns(data_source: pd.DataFrame) -> pd.Series: + """Sum the columns""" + return data_source.sum(axis=1) + +def average(sum_columns: pd.Series) -> float: + """Calculate average""" + return sum_columns.mean() + +# Build driver WITHOUT tracker for verification +dr = driver.Builder()\ + .with_modules(sys.modules[__name__])\ + .build() + +# Execute +result = dr.execute(["average"]) +print(f"✅ DAG executed successfully!") +print(f" Result: average = {result['average']}") + +assert result['average'] == 5.5, f"Expected 5.5, got {result['average']}" +print("✅ Result verified!") +EOF + +print_step "Step 7: Testing Hamilton DAG execution..." +python test_tracking.py +print_success "DAG execution verified" + +print_step "Step 8: Cleanup test files..." +rm -f test_tracking.py +print_success "Cleanup complete" + +echo "" +echo "============================================" +print_success "All verification steps passed!" +echo "============================================" +echo "" +echo "Summary:" +echo " ✅ Frontend built with npm install, npm build, cp -a" +echo " ✅ Build artifacts verified (index.html, static/)" +echo " ✅ Python package built with Flit" +echo " ✅ Package includes frontend assets" +echo " ✅ 12/12 build verification tests passed" +echo " ✅ Hamilton DAG execution works" +echo "" +echo "Next steps to test full tracking:" +echo " 1. Start UI server: export HAMILTON_ENV=mini && hamilton ui --port 8241" +echo " 2. Install SDK: pip install apache-hamilton-sdk" +echo " 3. Run DAG with tracker adapter" +echo " 4. Verify in browser: http://localhost:8241" From e59de917c80f73c68d294cb4ea6592ea140f1130 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sat, 4 Apr 2026 06:06:17 +0200 Subject: [PATCH 06/20] Remove license comments from databackend.py (#1535) * Remove license comments from databackend.py Removed Apache License comments from the file. * Fix pre-commit-config --------- Co-authored-by: Stefan Krawczyk --- .pre-commit-config.yaml | 6 +++--- hamilton/experimental/databackend.py | 17 ----------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cfd3b1247..9ea73c3ee 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -54,7 +54,8 @@ repos: ^\.github/| ^docs/| ^examples/| - ^dev_tools/language_server/tests/ls_setup\.py$ + ^dev_tools/language_server/tests/ls_setup\.py$| + ^hamilton/experimental/databackend.py$ args: - --comment-style - "|#|" @@ -69,8 +70,7 @@ repos: (?x) ^\.github/| ^docs/| - ^examples/| - ^hamilton/experimental/databackend.py + ^examples/ args: - --comment-style - "|#|" diff --git a/hamilton/experimental/databackend.py b/hamilton/experimental/databackend.py index ff1d1ebea..2eae6fbe7 100644 --- a/hamilton/experimental/databackend.py +++ b/hamilton/experimental/databackend.py @@ -1,20 +1,3 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - """Below is a file from `databackend` v0.0.2 found on GitHub permalink: https://github.com/machow/databackend/blob/214832bab6990098d52a4a2fae935f5d9ae8dc3c/databackend/__init__.py """ From 4a8c7442aa235f783045d89a520b774ee111419a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:14 -0700 Subject: [PATCH 07/20] Bump lodash from 4.17.23 to 4.18.1 in /contrib/docs (#1538) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.23 to 4.18.1. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.18.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- contrib/docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/docs/package-lock.json b/contrib/docs/package-lock.json index 46e51d6c8..480a35df7 100644 --- a/contrib/docs/package-lock.json +++ b/contrib/docs/package-lock.json @@ -10503,9 +10503,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.debounce": { From af49f792491f772bf707370f494667564d503ed9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:17 -0700 Subject: [PATCH 08/20] Bump brace-expansion from 1.1.12 to 1.1.13 in /contrib/docs (#1537) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.13. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- contrib/docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/docs/package-lock.json b/contrib/docs/package-lock.json index 480a35df7..bccafeb6f 100644 --- a/contrib/docs/package-lock.json +++ b/contrib/docs/package-lock.json @@ -6355,9 +6355,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", From 6d942795f2a1db8f99212ad8a21895606afc9e76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:20 -0700 Subject: [PATCH 09/20] Bump aiohttp from 3.13.3 to 3.13.4 in /ui/backend (#1536) --- updated-dependencies: - dependency-name: aiohttp dependency-version: 3.13.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/backend/uv.lock | 208 ++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/ui/backend/uv.lock b/ui/backend/uv.lock index 914473b36..bb53f3cee 100644 --- a/ui/backend/uv.lock +++ b/ui/backend/uv.lock @@ -37,7 +37,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.13.3" +version = "3.13.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -49,110 +49,110 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/4a/064321452809dae953c1ed6e017504e72551a26b6f5708a5a80e4bf556ff/aiohttp-3.13.4.tar.gz", hash = "sha256:d97a6d09c66087890c2ab5d49069e1e570583f7ac0314ecf98294c1b6aaebd38", size = 7859748, upload-time = "2026-03-28T17:19:40.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950, upload-time = "2026-01-03T17:29:13.002Z" }, - { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099, upload-time = "2026-01-03T17:29:15.268Z" }, - { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072, upload-time = "2026-01-03T17:29:16.922Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588, upload-time = "2026-01-03T17:29:18.539Z" }, - { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334, upload-time = "2026-01-03T17:29:21.028Z" }, - { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656, upload-time = "2026-01-03T17:29:22.531Z" }, - { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625, upload-time = "2026-01-03T17:29:24.276Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604, upload-time = "2026-01-03T17:29:26.099Z" }, - { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370, upload-time = "2026-01-03T17:29:28.121Z" }, - { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023, upload-time = "2026-01-03T17:29:30.002Z" }, - { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680, upload-time = "2026-01-03T17:29:31.782Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407, upload-time = "2026-01-03T17:29:33.392Z" }, - { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047, upload-time = "2026-01-03T17:29:34.855Z" }, - { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264, upload-time = "2026-01-03T17:29:36.389Z" }, - { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275, upload-time = "2026-01-03T17:29:38.162Z" }, - { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053, upload-time = "2026-01-03T17:29:40.074Z" }, - { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687, upload-time = "2026-01-03T17:29:41.819Z" }, - { url = "https://files.pythonhosted.org/packages/f1/4c/a164164834f03924d9a29dc3acd9e7ee58f95857e0b467f6d04298594ebb/aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b", size = 746051, upload-time = "2026-01-03T17:29:43.287Z" }, - { url = "https://files.pythonhosted.org/packages/82/71/d5c31390d18d4f58115037c432b7e0348c60f6f53b727cad33172144a112/aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64", size = 499234, upload-time = "2026-01-03T17:29:44.822Z" }, - { url = "https://files.pythonhosted.org/packages/0e/c9/741f8ac91e14b1d2e7100690425a5b2b919a87a5075406582991fb7de920/aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea", size = 494979, upload-time = "2026-01-03T17:29:46.405Z" }, - { url = "https://files.pythonhosted.org/packages/75/b5/31d4d2e802dfd59f74ed47eba48869c1c21552c586d5e81a9d0d5c2ad640/aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a", size = 1748297, upload-time = "2026-01-03T17:29:48.083Z" }, - { url = "https://files.pythonhosted.org/packages/1a/3e/eefad0ad42959f226bb79664826883f2687d602a9ae2941a18e0484a74d3/aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540", size = 1707172, upload-time = "2026-01-03T17:29:49.648Z" }, - { url = "https://files.pythonhosted.org/packages/c5/3a/54a64299fac2891c346cdcf2aa6803f994a2e4beeaf2e5a09dcc54acc842/aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b", size = 1805405, upload-time = "2026-01-03T17:29:51.244Z" }, - { url = "https://files.pythonhosted.org/packages/6c/70/ddc1b7169cf64075e864f64595a14b147a895a868394a48f6a8031979038/aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3", size = 1899449, upload-time = "2026-01-03T17:29:53.938Z" }, - { url = "https://files.pythonhosted.org/packages/a1/7e/6815aab7d3a56610891c76ef79095677b8b5be6646aaf00f69b221765021/aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1", size = 1748444, upload-time = "2026-01-03T17:29:55.484Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f2/073b145c4100da5511f457dc0f7558e99b2987cf72600d42b559db856fbc/aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3", size = 1606038, upload-time = "2026-01-03T17:29:57.179Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c1/778d011920cae03ae01424ec202c513dc69243cf2db303965615b81deeea/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440", size = 1724156, upload-time = "2026-01-03T17:29:58.914Z" }, - { url = "https://files.pythonhosted.org/packages/0e/cb/3419eabf4ec1e9ec6f242c32b689248365a1cf621891f6f0386632525494/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7", size = 1722340, upload-time = "2026-01-03T17:30:01.962Z" }, - { url = "https://files.pythonhosted.org/packages/7a/e5/76cf77bdbc435bf233c1f114edad39ed4177ccbfab7c329482b179cff4f4/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c", size = 1783041, upload-time = "2026-01-03T17:30:03.609Z" }, - { url = "https://files.pythonhosted.org/packages/9d/d4/dd1ca234c794fd29c057ce8c0566b8ef7fd6a51069de5f06fa84b9a1971c/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51", size = 1596024, upload-time = "2026-01-03T17:30:05.132Z" }, - { url = "https://files.pythonhosted.org/packages/55/58/4345b5f26661a6180afa686c473620c30a66afdf120ed3dd545bbc809e85/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4", size = 1804590, upload-time = "2026-01-03T17:30:07.135Z" }, - { url = "https://files.pythonhosted.org/packages/7b/06/05950619af6c2df7e0a431d889ba2813c9f0129cec76f663e547a5ad56f2/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29", size = 1740355, upload-time = "2026-01-03T17:30:09.083Z" }, - { url = "https://files.pythonhosted.org/packages/3e/80/958f16de79ba0422d7c1e284b2abd0c84bc03394fbe631d0a39ffa10e1eb/aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239", size = 433701, upload-time = "2026-01-03T17:30:10.869Z" }, - { url = "https://files.pythonhosted.org/packages/dc/f2/27cdf04c9851712d6c1b99df6821a6623c3c9e55956d4b1e318c337b5a48/aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f", size = 457678, upload-time = "2026-01-03T17:30:12.719Z" }, - { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" }, - { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" }, - { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" }, - { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" }, - { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" }, - { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" }, - { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" }, - { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" }, - { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" }, - { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" }, - { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" }, - { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" }, - { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" }, - { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload-time = "2026-01-03T17:30:45.832Z" }, - { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload-time = "2026-01-03T17:30:47.466Z" }, - { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload-time = "2026-01-03T17:30:49.373Z" }, - { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload-time = "2026-01-03T17:30:50.974Z" }, - { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload-time = "2026-01-03T17:30:52.729Z" }, - { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload-time = "2026-01-03T17:30:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload-time = "2026-01-03T17:30:56.512Z" }, - { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload-time = "2026-01-03T17:30:58.256Z" }, - { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload-time = "2026-01-03T17:31:00.445Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload-time = "2026-01-03T17:31:03.024Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload-time = "2026-01-03T17:31:04.842Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload-time = "2026-01-03T17:31:06.868Z" }, - { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload-time = "2026-01-03T17:31:08.958Z" }, - { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload-time = "2026-01-03T17:31:10.676Z" }, - { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload-time = "2026-01-03T17:31:12.575Z" }, - { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload-time = "2026-01-03T17:31:14.382Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload-time = "2026-01-03T17:31:15.958Z" }, - { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238, upload-time = "2026-01-03T17:31:17.909Z" }, - { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292, upload-time = "2026-01-03T17:31:19.919Z" }, - { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021, upload-time = "2026-01-03T17:31:21.636Z" }, - { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263, upload-time = "2026-01-03T17:31:23.296Z" }, - { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107, upload-time = "2026-01-03T17:31:25.334Z" }, - { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196, upload-time = "2026-01-03T17:31:27.394Z" }, - { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591, upload-time = "2026-01-03T17:31:29.238Z" }, - { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277, upload-time = "2026-01-03T17:31:31.053Z" }, - { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575, upload-time = "2026-01-03T17:31:32.87Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455, upload-time = "2026-01-03T17:31:34.76Z" }, - { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417, upload-time = "2026-01-03T17:31:36.699Z" }, - { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968, upload-time = "2026-01-03T17:31:38.622Z" }, - { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690, upload-time = "2026-01-03T17:31:40.57Z" }, - { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390, upload-time = "2026-01-03T17:31:42.857Z" }, - { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188, upload-time = "2026-01-03T17:31:44.984Z" }, - { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126, upload-time = "2026-01-03T17:31:47.463Z" }, - { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128, upload-time = "2026-01-03T17:31:49.2Z" }, - { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512, upload-time = "2026-01-03T17:31:51.134Z" }, - { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444, upload-time = "2026-01-03T17:31:52.85Z" }, - { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798, upload-time = "2026-01-03T17:31:54.91Z" }, - { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835, upload-time = "2026-01-03T17:31:56.733Z" }, - { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486, upload-time = "2026-01-03T17:31:58.65Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951, upload-time = "2026-01-03T17:32:00.989Z" }, - { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001, upload-time = "2026-01-03T17:32:03.122Z" }, - { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246, upload-time = "2026-01-03T17:32:05.255Z" }, - { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131, upload-time = "2026-01-03T17:32:07.607Z" }, - { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196, upload-time = "2026-01-03T17:32:09.59Z" }, - { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841, upload-time = "2026-01-03T17:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193, upload-time = "2026-01-03T17:32:13.705Z" }, - { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979, upload-time = "2026-01-03T17:32:15.965Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193, upload-time = "2026-01-03T17:32:18.219Z" }, - { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" }, + { url = "https://files.pythonhosted.org/packages/2c/05/6817e0390eb47b0867cf8efdb535298191662192281bc3ca62a0cb7973eb/aiohttp-3.13.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6290fe12fe8cefa6ea3c1c5b969d32c010dfe191d4392ff9b599a3f473cbe722", size = 753094, upload-time = "2026-03-28T17:14:59.928Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/e5b7f25f6dd1ab57da92aa9d226b2c8b56f223dd20475d3ddfddaba86ab8/aiohttp-3.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7520d92c0e8fbbe63f36f20a5762db349ff574ad38ad7bc7732558a650439845", size = 505213, upload-time = "2026-03-28T17:15:01.989Z" }, + { url = "https://files.pythonhosted.org/packages/b4/e5/8f42033c7ce98b54dfd3791f03e60231cfe4a2db4471b5fc188df2b8a6ad/aiohttp-3.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2710ae1e1b81d0f187883b6e9d66cecf8794b50e91aa1e73fc78bfb5503b5d9", size = 498580, upload-time = "2026-03-28T17:15:03.879Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/bbc989f5362066b81930da1a66084a859a971d03faab799dc59a3ce3a220/aiohttp-3.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:717d17347567ded1e273aa09918650dfd6fd06f461549204570c7973537d4123", size = 1692718, upload-time = "2026-03-28T17:15:05.541Z" }, + { url = "https://files.pythonhosted.org/packages/1c/72/3775116969931f151be116689d2ae6ddafff2ec2887d8f9b4e7043f32e74/aiohttp-3.13.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:383880f7b8de5ac208fa829c7038d08e66377283b2de9e791b71e06e803153c2", size = 1660714, upload-time = "2026-03-28T17:15:08.23Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e8/d2f1a2da2743e32fe348ebf8a4c59caad14a92f5f18af616fd33381275e1/aiohttp-3.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1867087e2c1963db1216aedf001efe3b129835ed2b05d97d058176a6d08b5726", size = 1744152, upload-time = "2026-03-28T17:15:10.828Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a6/575886f417ac3c08e462f2ca237cc49f436bd992ca3f7ff95b7dd9c44205/aiohttp-3.13.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6234bf416a38d687c3ab7f79934d7fb2a42117a5b9813aca07de0a5398489023", size = 1836278, upload-time = "2026-03-28T17:15:12.537Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4c/0051d4550fb9e8b5ca4e0fe1ccd58652340915180c5164999e6741bf2083/aiohttp-3.13.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3cdd3393130bf6588962441ffd5bde1d3ea2d63a64afa7119b3f3ba349cebbe7", size = 1687953, upload-time = "2026-03-28T17:15:14.248Z" }, + { url = "https://files.pythonhosted.org/packages/c9/54/841e87b8c51c2adc01a3ceb9919dc45c7899fe4c21deb70aada734ea5a38/aiohttp-3.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d0dbc6c76befa76865373d6aa303e480bb8c3486e7763530f7f6e527b471118", size = 1572484, upload-time = "2026-03-28T17:15:15.911Z" }, + { url = "https://files.pythonhosted.org/packages/da/f1/21cbf5f7fa1e267af6301f886cab9b314f085e4d0097668d189d165cd7da/aiohttp-3.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10fb7b53262cf4144a083c9db0d2b4d22823d6708270a9970c4627b248c6064c", size = 1662851, upload-time = "2026-03-28T17:15:17.822Z" }, + { url = "https://files.pythonhosted.org/packages/40/15/bcad6b68d7bef27ae7443288215767263c7753ede164267cf6cf63c94a87/aiohttp-3.13.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:eb10ce8c03850e77f4d9518961c227be569e12f71525a7e90d17bca04299921d", size = 1671984, upload-time = "2026-03-28T17:15:19.561Z" }, + { url = "https://files.pythonhosted.org/packages/ff/fa/ab316931afc7a73c7f493bb1b30fbd61e28ec2d3ea50353336e76293e8ec/aiohttp-3.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7c65738ac5ae32b8feef699a4ed0dc91a0c8618b347781b7461458bbcaaac7eb", size = 1713880, upload-time = "2026-03-28T17:15:21.589Z" }, + { url = "https://files.pythonhosted.org/packages/1c/45/314e8e64c7f328174964b6db511dd5e9e60c9121ab5457bc2c908b7d03a4/aiohttp-3.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:6b335919ffbaf98df8ff3c74f7a6decb8775882632952fd1810a017e38f15aee", size = 1560315, upload-time = "2026-03-28T17:15:23.66Z" }, + { url = "https://files.pythonhosted.org/packages/18/e7/93d5fa06fe00219a81466577dacae9e3732f3b4f767b12b2e2cc8c35c970/aiohttp-3.13.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ec75fc18cb9f4aca51c2cbace20cf6716e36850f44189644d2d69a875d5e0532", size = 1735115, upload-time = "2026-03-28T17:15:25.77Z" }, + { url = "https://files.pythonhosted.org/packages/19/9f/f64b95392ddd4e204fd9ab7cd33dd18d14ac9e4b86866f1f6a69b7cda83d/aiohttp-3.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:463fa18a95c5a635d2b8c09babe240f9d7dbf2a2010a6c0b35d8c4dff2a0e819", size = 1673916, upload-time = "2026-03-28T17:15:27.526Z" }, + { url = "https://files.pythonhosted.org/packages/52/c1/bb33be79fd285c69f32e5b074b299cae8847f748950149c3965c1b3b3adf/aiohttp-3.13.4-cp310-cp310-win32.whl", hash = "sha256:13168f5645d9045522c6cef818f54295376257ed8d02513a37c2ef3046fc7a97", size = 440277, upload-time = "2026-03-28T17:15:29.173Z" }, + { url = "https://files.pythonhosted.org/packages/23/f9/7cf1688da4dd0885f914ee40bc8e1dce776df98fe6518766de975a570538/aiohttp-3.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:a7058af1f53209fdf07745579ced525d38d481650a989b7aa4a3b484b901cdab", size = 463015, upload-time = "2026-03-28T17:15:30.802Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7e/cb94129302d78c46662b47f9897d642fd0b33bdfef4b73b20c6ced35aa4c/aiohttp-3.13.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8ea0c64d1bcbf201b285c2246c51a0c035ba3bbd306640007bc5844a3b4658c1", size = 760027, upload-time = "2026-03-28T17:15:33.022Z" }, + { url = "https://files.pythonhosted.org/packages/5e/cd/2db3c9397c3bd24216b203dd739945b04f8b87bb036c640da7ddb63c75ef/aiohttp-3.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6f742e1fa45c0ed522b00ede565e18f97e4cf8d1883a712ac42d0339dfb0cce7", size = 508325, upload-time = "2026-03-28T17:15:34.714Z" }, + { url = "https://files.pythonhosted.org/packages/36/a3/d28b2722ec13107f2e37a86b8a169897308bab6a3b9e071ecead9d67bd9b/aiohttp-3.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dcfb50ee25b3b7a1222a9123be1f9f89e56e67636b561441f0b304e25aaef8f", size = 502402, upload-time = "2026-03-28T17:15:36.409Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d6/acd47b5f17c4430e555590990a4746efbcb2079909bb865516892bf85f37/aiohttp-3.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3262386c4ff370849863ea93b9ea60fd59c6cf56bf8f93beac625cf4d677c04d", size = 1771224, upload-time = "2026-03-28T17:15:38.223Z" }, + { url = "https://files.pythonhosted.org/packages/98/af/af6e20113ba6a48fd1cd9e5832c4851e7613ef50c7619acdaee6ec5f1aff/aiohttp-3.13.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:473bb5aa4218dd254e9ae4834f20e31f5a0083064ac0136a01a62ddbae2eaa42", size = 1731530, upload-time = "2026-03-28T17:15:39.988Z" }, + { url = "https://files.pythonhosted.org/packages/81/16/78a2f5d9c124ad05d5ce59a9af94214b6466c3491a25fb70760e98e9f762/aiohttp-3.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e56423766399b4c77b965f6aaab6c9546617b8994a956821cc507d00b91d978c", size = 1827925, upload-time = "2026-03-28T17:15:41.944Z" }, + { url = "https://files.pythonhosted.org/packages/2a/1f/79acf0974ced805e0e70027389fccbb7d728e6f30fcac725fb1071e63075/aiohttp-3.13.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8af249343fafd5ad90366a16d230fc265cf1149f26075dc9fe93cfd7c7173942", size = 1923579, upload-time = "2026-03-28T17:15:44.071Z" }, + { url = "https://files.pythonhosted.org/packages/af/53/29f9e2054ea6900413f3b4c3eb9d8331f60678ec855f13ba8714c47fd48d/aiohttp-3.13.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bc0a5cf4f10ef5a2c94fdde488734b582a3a7a000b131263e27c9295bd682d9", size = 1767655, upload-time = "2026-03-28T17:15:45.911Z" }, + { url = "https://files.pythonhosted.org/packages/f3/57/462fe1d3da08109ba4aa8590e7aed57c059af2a7e80ec21f4bac5cfe1094/aiohttp-3.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5c7ff1028e3c9fc5123a865ce17df1cb6424d180c503b8517afbe89aa566e6be", size = 1630439, upload-time = "2026-03-28T17:15:48.11Z" }, + { url = "https://files.pythonhosted.org/packages/d7/4b/4813344aacdb8127263e3eec343d24e973421143826364fa9fc847f6283f/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ba5cf98b5dcb9bddd857da6713a503fa6d341043258ca823f0f5ab7ab4a94ee8", size = 1745557, upload-time = "2026-03-28T17:15:50.13Z" }, + { url = "https://files.pythonhosted.org/packages/d4/01/1ef1adae1454341ec50a789f03cfafe4c4ac9c003f6a64515ecd32fe4210/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d85965d3ba21ee4999e83e992fecb86c4614d6920e40705501c0a1f80a583c12", size = 1741796, upload-time = "2026-03-28T17:15:52.351Z" }, + { url = "https://files.pythonhosted.org/packages/22/04/8cdd99af988d2aa6922714d957d21383c559835cbd43fbf5a47ddf2e0f05/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:49f0b18a9b05d79f6f37ddd567695943fcefb834ef480f17a4211987302b2dc7", size = 1805312, upload-time = "2026-03-28T17:15:54.407Z" }, + { url = "https://files.pythonhosted.org/packages/fb/7f/b48d5577338d4b25bbdbae35c75dbfd0493cb8886dc586fbfb2e90862239/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7f78cb080c86fbf765920e5f1ef35af3f24ec4314d6675d0a21eaf41f6f2679c", size = 1621751, upload-time = "2026-03-28T17:15:56.564Z" }, + { url = "https://files.pythonhosted.org/packages/bc/89/4eecad8c1858e6d0893c05929e22343e0ebe3aec29a8a399c65c3cc38311/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:67a3ec705534a614b68bbf1c70efa777a21c3da3895d1c44510a41f5a7ae0453", size = 1826073, upload-time = "2026-03-28T17:15:58.489Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5c/9dc8293ed31b46c39c9c513ac7ca152b3c3d38e0ea111a530ad12001b827/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d6630ec917e85c5356b2295744c8a97d40f007f96a1c76bf1928dc2e27465393", size = 1760083, upload-time = "2026-03-28T17:16:00.677Z" }, + { url = "https://files.pythonhosted.org/packages/1e/19/8bbf6a4994205d96831f97b7d21a0feed120136e6267b5b22d229c6dc4dc/aiohttp-3.13.4-cp311-cp311-win32.whl", hash = "sha256:54049021bc626f53a5394c29e8c444f726ee5a14b6e89e0ad118315b1f90f5e3", size = 439690, upload-time = "2026-03-28T17:16:02.902Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f5/ac409ecd1007528d15c3e8c3a57d34f334c70d76cfb7128a28cffdebd4c1/aiohttp-3.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:c033f2bc964156030772d31cbf7e5defea181238ce1f87b9455b786de7d30145", size = 463824, upload-time = "2026-03-28T17:16:05.058Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bd/ede278648914cabbabfdf95e436679b5d4156e417896a9b9f4587169e376/aiohttp-3.13.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ee62d4471ce86b108b19c3364db4b91180d13fe3510144872d6bad5401957360", size = 752158, upload-time = "2026-03-28T17:16:06.901Z" }, + { url = "https://files.pythonhosted.org/packages/90/de/581c053253c07b480b03785196ca5335e3c606a37dc73e95f6527f1591fe/aiohttp-3.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c0fd8f41b54b58636402eb493afd512c23580456f022c1ba2db0f810c959ed0d", size = 501037, upload-time = "2026-03-28T17:16:08.82Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/a5ede193c08f13cc42c0a5b50d1e246ecee9115e4cf6e900d8dbd8fd6acb/aiohttp-3.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4baa48ce49efd82d6b1a0be12d6a36b35e5594d1dd42f8bfba96ea9f8678b88c", size = 501556, upload-time = "2026-03-28T17:16:10.63Z" }, + { url = "https://files.pythonhosted.org/packages/d6/10/88ff67cd48a6ec36335b63a640abe86135791544863e0cfe1f065d6cef7a/aiohttp-3.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d738ebab9f71ee652d9dbd0211057690022201b11197f9a7324fd4dba128aa97", size = 1757314, upload-time = "2026-03-28T17:16:12.498Z" }, + { url = "https://files.pythonhosted.org/packages/8b/15/fdb90a5cf5a1f52845c276e76298c75fbbcc0ac2b4a86551906d54529965/aiohttp-3.13.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0ce692c3468fa831af7dceed52edf51ac348cebfc8d3feb935927b63bd3e8576", size = 1731819, upload-time = "2026-03-28T17:16:14.558Z" }, + { url = "https://files.pythonhosted.org/packages/ec/df/28146785a007f7820416be05d4f28cc207493efd1e8c6c1068e9bdc29198/aiohttp-3.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e08abcfe752a454d2cb89ff0c08f2d1ecd057ae3e8cc6d84638de853530ebab", size = 1793279, upload-time = "2026-03-28T17:16:16.594Z" }, + { url = "https://files.pythonhosted.org/packages/10/47/689c743abf62ea7a77774d5722f220e2c912a77d65d368b884d9779ef41b/aiohttp-3.13.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5977f701b3fff36367a11087f30ea73c212e686d41cd363c50c022d48b011d8d", size = 1891082, upload-time = "2026-03-28T17:16:18.71Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b6/f7f4f318c7e58c23b761c9b13b9a3c9b394e0f9d5d76fbc6622fa98509f6/aiohttp-3.13.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54203e10405c06f8b6020bd1e076ae0fe6c194adcee12a5a78af3ffa3c57025e", size = 1773938, upload-time = "2026-03-28T17:16:21.125Z" }, + { url = "https://files.pythonhosted.org/packages/aa/06/f207cb3121852c989586a6fc16ff854c4fcc8651b86c5d3bd1fc83057650/aiohttp-3.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:358a6af0145bc4dda037f13167bef3cce54b132087acc4c295c739d05d16b1c3", size = 1579548, upload-time = "2026-03-28T17:16:23.588Z" }, + { url = "https://files.pythonhosted.org/packages/6c/58/e1289661a32161e24c1fe479711d783067210d266842523752869cc1d9c2/aiohttp-3.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:898ea1850656d7d61832ef06aa9846ab3ddb1621b74f46de78fbc5e1a586ba83", size = 1714669, upload-time = "2026-03-28T17:16:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/96/0a/3e86d039438a74a86e6a948a9119b22540bae037d6ba317a042ae3c22711/aiohttp-3.13.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7bc30cceb710cf6a44e9617e43eebb6e3e43ad855a34da7b4b6a73537d8a6763", size = 1754175, upload-time = "2026-03-28T17:16:28.18Z" }, + { url = "https://files.pythonhosted.org/packages/f4/30/e717fc5df83133ba467a560b6d8ef20197037b4bb5d7075b90037de1018e/aiohttp-3.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4a31c0c587a8a038f19a4c7e60654a6c899c9de9174593a13e7cc6e15ff271f9", size = 1762049, upload-time = "2026-03-28T17:16:30.941Z" }, + { url = "https://files.pythonhosted.org/packages/e4/28/8f7a2d4492e336e40005151bdd94baf344880a4707573378579f833a64c1/aiohttp-3.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2062f675f3fe6e06d6113eb74a157fb9df58953ffed0cdb4182554b116545758", size = 1570861, upload-time = "2026-03-28T17:16:32.953Z" }, + { url = "https://files.pythonhosted.org/packages/78/45/12e1a3d0645968b1c38de4b23fdf270b8637735ea057d4f84482ff918ad9/aiohttp-3.13.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d1ba8afb847ff80626d5e408c1fdc99f942acc877d0702fe137015903a220a9", size = 1790003, upload-time = "2026-03-28T17:16:35.468Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0f/60374e18d590de16dcb39d6ff62f39c096c1b958e6f37727b5870026ea30/aiohttp-3.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b08149419994cdd4d5eecf7fd4bc5986b5a9380285bcd01ab4c0d6bfca47b79d", size = 1737289, upload-time = "2026-03-28T17:16:38.187Z" }, + { url = "https://files.pythonhosted.org/packages/02/bf/535e58d886cfbc40a8b0013c974afad24ef7632d645bca0b678b70033a60/aiohttp-3.13.4-cp312-cp312-win32.whl", hash = "sha256:fc432f6a2c4f720180959bc19aa37259651c1a4ed8af8afc84dd41c60f15f791", size = 434185, upload-time = "2026-03-28T17:16:40.735Z" }, + { url = "https://files.pythonhosted.org/packages/1e/1a/d92e3325134ebfff6f4069f270d3aac770d63320bd1fcd0eca023e74d9a8/aiohttp-3.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:6148c9ae97a3e8bff9a1fc9c757fa164116f86c100468339730e717590a3fb77", size = 461285, upload-time = "2026-03-28T17:16:42.713Z" }, + { url = "https://files.pythonhosted.org/packages/e3/ac/892f4162df9b115b4758d615f32ec63d00f3084c705ff5526630887b9b42/aiohttp-3.13.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:63dd5e5b1e43b8fb1e91b79b7ceba1feba588b317d1edff385084fcc7a0a4538", size = 745744, upload-time = "2026-03-28T17:16:44.67Z" }, + { url = "https://files.pythonhosted.org/packages/97/a9/c5b87e4443a2f0ea88cb3000c93a8fdad1ee63bffc9ded8d8c8e0d66efc6/aiohttp-3.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:746ac3cc00b5baea424dacddea3ec2c2702f9590de27d837aa67004db1eebc6e", size = 498178, upload-time = "2026-03-28T17:16:46.766Z" }, + { url = "https://files.pythonhosted.org/packages/94/42/07e1b543a61250783650df13da8ddcdc0d0a5538b2bd15cef6e042aefc61/aiohttp-3.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bda8f16ea99d6a6705e5946732e48487a448be874e54a4f73d514660ff7c05d3", size = 498331, upload-time = "2026-03-28T17:16:48.9Z" }, + { url = "https://files.pythonhosted.org/packages/20/d6/492f46bf0328534124772d0cf58570acae5b286ea25006900650f69dae0e/aiohttp-3.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4b061e7b5f840391e3f64d0ddf672973e45c4cfff7a0feea425ea24e51530fc2", size = 1744414, upload-time = "2026-03-28T17:16:50.968Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4d/e02627b2683f68051246215d2d62b2d2f249ff7a285e7a858dc47d6b6a14/aiohttp-3.13.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b252e8d5cd66184b570d0d010de742736e8a4fab22c58299772b0c5a466d4b21", size = 1719226, upload-time = "2026-03-28T17:16:53.173Z" }, + { url = "https://files.pythonhosted.org/packages/7b/6c/5d0a3394dd2b9f9aeba6e1b6065d0439e4b75d41f1fb09a3ec010b43552b/aiohttp-3.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:20af8aad61d1803ff11152a26146d8d81c266aa8c5aa9b4504432abb965c36a0", size = 1782110, upload-time = "2026-03-28T17:16:55.362Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2d/c20791e3437700a7441a7edfb59731150322424f5aadf635602d1d326101/aiohttp-3.13.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:13a5cc924b59859ad2adb1478e31f410a7ed46e92a2a619d6d1dd1a63c1a855e", size = 1884809, upload-time = "2026-03-28T17:16:57.734Z" }, + { url = "https://files.pythonhosted.org/packages/c8/94/d99dbfbd1924a87ef643833932eb2a3d9e5eee87656efea7d78058539eff/aiohttp-3.13.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:534913dfb0a644d537aebb4123e7d466d94e3be5549205e6a31f72368980a81a", size = 1764938, upload-time = "2026-03-28T17:17:00.221Z" }, + { url = "https://files.pythonhosted.org/packages/49/61/3ce326a1538781deb89f6cf5e094e2029cd308ed1e21b2ba2278b08426f6/aiohttp-3.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:320e40192a2dcc1cf4b5576936e9652981ab596bf81eb309535db7e2f5b5672f", size = 1570697, upload-time = "2026-03-28T17:17:02.985Z" }, + { url = "https://files.pythonhosted.org/packages/b6/77/4ab5a546857bb3028fbaf34d6eea180267bdab022ee8b1168b1fcde4bfdd/aiohttp-3.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9e587fcfce2bcf06526a43cb705bdee21ac089096f2e271d75de9c339db3100c", size = 1702258, upload-time = "2026-03-28T17:17:05.28Z" }, + { url = "https://files.pythonhosted.org/packages/79/63/d8f29021e39bc5af8e5d5e9da1b07976fb9846487a784e11e4f4eeda4666/aiohttp-3.13.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9eb9c2eea7278206b5c6c1441fdd9dc420c278ead3f3b2cc87f9b693698cc500", size = 1740287, upload-time = "2026-03-28T17:17:07.712Z" }, + { url = "https://files.pythonhosted.org/packages/55/3a/cbc6b3b124859a11bc8055d3682c26999b393531ef926754a3445b99dfef/aiohttp-3.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:29be00c51972b04bf9d5c8f2d7f7314f48f96070ca40a873a53056e652e805f7", size = 1753011, upload-time = "2026-03-28T17:17:10.053Z" }, + { url = "https://files.pythonhosted.org/packages/e0/30/836278675205d58c1368b21520eab9572457cf19afd23759216c04483048/aiohttp-3.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:90c06228a6c3a7c9f776fe4fc0b7ff647fffd3bed93779a6913c804ae00c1073", size = 1566359, upload-time = "2026-03-28T17:17:12.433Z" }, + { url = "https://files.pythonhosted.org/packages/50/b4/8032cc9b82d17e4277704ba30509eaccb39329dc18d6a35f05e424439e32/aiohttp-3.13.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a533ec132f05fd9a1d959e7f34184cd7d5e8511584848dab85faefbaac573069", size = 1785537, upload-time = "2026-03-28T17:17:14.721Z" }, + { url = "https://files.pythonhosted.org/packages/17/7d/5873e98230bde59f493bf1f7c3e327486a4b5653fa401144704df5d00211/aiohttp-3.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1c946f10f413836f82ea4cfb90200d2a59578c549f00857e03111cf45ad01ca5", size = 1740752, upload-time = "2026-03-28T17:17:17.387Z" }, + { url = "https://files.pythonhosted.org/packages/7b/f2/13e46e0df051494d7d3c68b7f72d071f48c384c12716fc294f75d5b1a064/aiohttp-3.13.4-cp313-cp313-win32.whl", hash = "sha256:48708e2706106da6967eff5908c78ca3943f005ed6bcb75da2a7e4da94ef8c70", size = 433187, upload-time = "2026-03-28T17:17:19.523Z" }, + { url = "https://files.pythonhosted.org/packages/ea/c0/649856ee655a843c8f8664592cfccb73ac80ede6a8c8db33a25d810c12db/aiohttp-3.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:74a2eb058da44fa3a877a49e2095b591d4913308bb424c418b77beb160c55ce3", size = 459778, upload-time = "2026-03-28T17:17:21.964Z" }, + { url = "https://files.pythonhosted.org/packages/6d/29/6657cc37ae04cacc2dbf53fb730a06b6091cc4cbe745028e047c53e6d840/aiohttp-3.13.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:e0a2c961fc92abeff61d6444f2ce6ad35bb982db9fc8ff8a47455beacf454a57", size = 749363, upload-time = "2026-03-28T17:17:24.044Z" }, + { url = "https://files.pythonhosted.org/packages/90/7f/30ccdf67ca3d24b610067dc63d64dcb91e5d88e27667811640644aa4a85d/aiohttp-3.13.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:153274535985a0ff2bff1fb6c104ed547cec898a09213d21b0f791a44b14d933", size = 499317, upload-time = "2026-03-28T17:17:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/93/13/e372dd4e68ad04ee25dafb050c7f98b0d91ea643f7352757e87231102555/aiohttp-3.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:351f3171e2458da3d731ce83f9e6b9619e325c45cbd534c7759750cabf453ad7", size = 500477, upload-time = "2026-03-28T17:17:28.279Z" }, + { url = "https://files.pythonhosted.org/packages/e5/fe/ee6298e8e586096fb6f5eddd31393d8544f33ae0792c71ecbb4c2bef98ac/aiohttp-3.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f989ac8bc5595ff761a5ccd32bdb0768a117f36dd1504b1c2c074ed5d3f4df9c", size = 1737227, upload-time = "2026-03-28T17:17:30.587Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b9/a7a0463a09e1a3fe35100f74324f23644bfc3383ac5fd5effe0722a5f0b7/aiohttp-3.13.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d36fc1709110ec1e87a229b201dd3ddc32aa01e98e7868083a794609b081c349", size = 1694036, upload-time = "2026-03-28T17:17:33.29Z" }, + { url = "https://files.pythonhosted.org/packages/57/7c/8972ae3fb7be00a91aee6b644b2a6a909aedb2c425269a3bfd90115e6f8f/aiohttp-3.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42adaeea83cbdf069ab94f5103ce0787c21fb1a0153270da76b59d5578302329", size = 1786814, upload-time = "2026-03-28T17:17:36.035Z" }, + { url = "https://files.pythonhosted.org/packages/93/01/c81e97e85c774decbaf0d577de7d848934e8166a3a14ad9f8aa5be329d28/aiohttp-3.13.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:92deb95469928cc41fd4b42a95d8012fa6df93f6b1c0a83af0ffbc4a5e218cde", size = 1866676, upload-time = "2026-03-28T17:17:38.441Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5f/5b46fe8694a639ddea2cd035bf5729e4677ea882cb251396637e2ef1590d/aiohttp-3.13.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0c7c07c4257ef3a1df355f840bc62d133bcdef5c1c5ba75add3c08553e2eed", size = 1740842, upload-time = "2026-03-28T17:17:40.783Z" }, + { url = "https://files.pythonhosted.org/packages/20/a2/0d4b03d011cca6b6b0acba8433193c1e484efa8d705ea58295590fe24203/aiohttp-3.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f062c45de8a1098cb137a1898819796a2491aec4e637a06b03f149315dff4d8f", size = 1566508, upload-time = "2026-03-28T17:17:43.235Z" }, + { url = "https://files.pythonhosted.org/packages/98/17/e689fd500da52488ec5f889effd6404dece6a59de301e380f3c64f167beb/aiohttp-3.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:76093107c531517001114f0ebdb4f46858ce818590363e3e99a4a2280334454a", size = 1700569, upload-time = "2026-03-28T17:17:46.165Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0d/66402894dbcf470ef7db99449e436105ea862c24f7ea4c95c683e635af35/aiohttp-3.13.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:6f6ec32162d293b82f8b63a16edc80769662fbd5ae6fbd4936d3206a2c2cc63b", size = 1707407, upload-time = "2026-03-28T17:17:48.825Z" }, + { url = "https://files.pythonhosted.org/packages/2f/eb/af0ab1a3650092cbd8e14ef29e4ab0209e1460e1c299996c3f8288b3f1ff/aiohttp-3.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5903e2db3d202a00ad9f0ec35a122c005e85d90c9836ab4cda628f01edf425e2", size = 1752214, upload-time = "2026-03-28T17:17:51.206Z" }, + { url = "https://files.pythonhosted.org/packages/5a/bf/72326f8a98e4c666f292f03c385545963cc65e358835d2a7375037a97b57/aiohttp-3.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2d5bea57be7aca98dbbac8da046d99b5557c5cf4e28538c4c786313078aca09e", size = 1562162, upload-time = "2026-03-28T17:17:53.634Z" }, + { url = "https://files.pythonhosted.org/packages/67/9f/13b72435f99151dd9a5469c96b3b5f86aa29b7e785ca7f35cf5e538f74c0/aiohttp-3.13.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:bcf0c9902085976edc0232b75006ef38f89686901249ce14226b6877f88464fb", size = 1768904, upload-time = "2026-03-28T17:17:55.991Z" }, + { url = "https://files.pythonhosted.org/packages/18/bc/28d4970e7d5452ac7776cdb5431a1164a0d9cf8bd2fffd67b4fb463aa56d/aiohttp-3.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3295f98bfeed2e867cab588f2a146a9db37a85e3ae9062abf46ba062bd29165", size = 1723378, upload-time = "2026-03-28T17:17:58.348Z" }, + { url = "https://files.pythonhosted.org/packages/53/74/b32458ca1a7f34d65bdee7aef2036adbe0438123d3d53e2b083c453c24dd/aiohttp-3.13.4-cp314-cp314-win32.whl", hash = "sha256:a598a5c5767e1369d8f5b08695cab1d8160040f796c4416af76fd773d229b3c9", size = 438711, upload-time = "2026-03-28T17:18:00.728Z" }, + { url = "https://files.pythonhosted.org/packages/40/b2/54b487316c2df3e03a8f3435e9636f8a81a42a69d942164830d193beb56a/aiohttp-3.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:c555db4bc7a264bead5a7d63d92d41a1122fcd39cc62a4db815f45ad46f9c2c8", size = 464977, upload-time = "2026-03-28T17:18:03.367Z" }, + { url = "https://files.pythonhosted.org/packages/47/fb/e41b63c6ce71b07a59243bb8f3b457ee0c3402a619acb9d2c0d21ef0e647/aiohttp-3.13.4-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45abbbf09a129825d13c18c7d3182fecd46d9da3cfc383756145394013604ac1", size = 781549, upload-time = "2026-03-28T17:18:05.779Z" }, + { url = "https://files.pythonhosted.org/packages/97/53/532b8d28df1e17e44c4d9a9368b78dcb6bf0b51037522136eced13afa9e8/aiohttp-3.13.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:74c80b2bc2c2adb7b3d1941b2b60701ee2af8296fc8aad8b8bc48bc25767266c", size = 514383, upload-time = "2026-03-28T17:18:08.096Z" }, + { url = "https://files.pythonhosted.org/packages/1b/1f/62e5d400603e8468cd635812d99cb81cfdc08127a3dc474c647615f31339/aiohttp-3.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c97989ae40a9746650fa196894f317dafc12227c808c774929dda0ff873a5954", size = 518304, upload-time = "2026-03-28T17:18:10.642Z" }, + { url = "https://files.pythonhosted.org/packages/90/57/2326b37b10896447e3c6e0cbef4fe2486d30913639a5cfd1332b5d870f82/aiohttp-3.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dae86be9811493f9990ef44fff1685f5c1a3192e9061a71a109d527944eed551", size = 1893433, upload-time = "2026-03-28T17:18:13.121Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b4/a24d82112c304afdb650167ef2fe190957d81cbddac7460bedd245f765aa/aiohttp-3.13.4-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1db491abe852ca2fa6cc48a3341985b0174b3741838e1341b82ac82c8bd9e871", size = 1755901, upload-time = "2026-03-28T17:18:16.21Z" }, + { url = "https://files.pythonhosted.org/packages/9e/2d/0883ef9d878d7846287f036c162a951968f22aabeef3ac97b0bea6f76d5d/aiohttp-3.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e5d701c0aad02a7dce72eef6b93226cf3734330f1a31d69ebbf69f33b86666e", size = 1876093, upload-time = "2026-03-28T17:18:18.703Z" }, + { url = "https://files.pythonhosted.org/packages/ad/52/9204bb59c014869b71971addad6778f005daa72a96eed652c496789d7468/aiohttp-3.13.4-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8ac32a189081ae0a10ba18993f10f338ec94341f0d5df8fff348043962f3c6f8", size = 1970815, upload-time = "2026-03-28T17:18:21.858Z" }, + { url = "https://files.pythonhosted.org/packages/d6/b5/e4eb20275a866dde0f570f411b36c6b48f7b53edfe4f4071aa1b0728098a/aiohttp-3.13.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98e968cdaba43e45c73c3f306fca418c8009a957733bac85937c9f9cf3f4de27", size = 1816223, upload-time = "2026-03-28T17:18:24.729Z" }, + { url = "https://files.pythonhosted.org/packages/d8/23/e98075c5bb146aa61a1239ee1ac7714c85e814838d6cebbe37d3fe19214a/aiohttp-3.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca114790c9144c335d538852612d3e43ea0f075288f4849cf4b05d6cd2238ce7", size = 1649145, upload-time = "2026-03-28T17:18:27.269Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c1/7bad8be33bb06c2bb224b6468874346026092762cbec388c3bdb65a368ee/aiohttp-3.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ea2e071661ba9cfe11eabbc81ac5376eaeb3061f6e72ec4cc86d7cdd1ffbdbbb", size = 1816562, upload-time = "2026-03-28T17:18:29.847Z" }, + { url = "https://files.pythonhosted.org/packages/5c/10/c00323348695e9a5e316825969c88463dcc24c7e9d443244b8a2c9cf2eae/aiohttp-3.13.4-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:34e89912b6c20e0fd80e07fa401fd218a410aa1ce9f1c2f1dad6db1bd0ce0927", size = 1800333, upload-time = "2026-03-28T17:18:32.269Z" }, + { url = "https://files.pythonhosted.org/packages/84/43/9b2147a1df3559f49bd723e22905b46a46c068a53adb54abdca32c4de180/aiohttp-3.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0e217cf9f6a42908c52b46e42c568bd57adc39c9286ced31aaace614b6087965", size = 1820617, upload-time = "2026-03-28T17:18:35.238Z" }, + { url = "https://files.pythonhosted.org/packages/a9/7f/b3481a81e7a586d02e99387b18c6dafff41285f6efd3daa2124c01f87eae/aiohttp-3.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:0c296f1221e21ba979f5ac1964c3b78cfde15c5c5f855ffd2caab337e9cd9182", size = 1643417, upload-time = "2026-03-28T17:18:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/8f/72/07181226bc99ce1124e0f89280f5221a82d3ae6a6d9d1973ce429d48e52b/aiohttp-3.13.4-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d99a9d168ebaffb74f36d011750e490085ac418f4db926cce3989c8fe6cb6b1b", size = 1849286, upload-time = "2026-03-28T17:18:40.534Z" }, + { url = "https://files.pythonhosted.org/packages/1a/e6/1b3566e103eca6da5be4ae6713e112a053725c584e96574caf117568ffef/aiohttp-3.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cb19177205d93b881f3f89e6081593676043a6828f59c78c17a0fd6c1fbed2ba", size = 1782635, upload-time = "2026-03-28T17:18:43.073Z" }, + { url = "https://files.pythonhosted.org/packages/37/58/1b11c71904b8d079eb0c39fe664180dd1e14bebe5608e235d8bfbadc8929/aiohttp-3.13.4-cp314-cp314t-win32.whl", hash = "sha256:c606aa5656dab6552e52ca368e43869c916338346bfaf6304e15c58fb113ea30", size = 472537, upload-time = "2026-03-28T17:18:46.286Z" }, + { url = "https://files.pythonhosted.org/packages/bc/8f/87c56a1a1977d7dddea5b31e12189665a140fdb48a71e9038ff90bb564ec/aiohttp-3.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:014dcc10ec8ab8db681f0d68e939d1e9286a5aa2b993cbbdb0db130853e02144", size = 506381, upload-time = "2026-03-28T17:18:48.74Z" }, ] [[package]] From a404380d948fdbcae1088202ccc4811bbba4960e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:23 -0700 Subject: [PATCH 10/20] Bump pygments from 2.19.2 to 2.20.0 in /ui/backend (#1534) Bumps [pygments](https://github.com/pygments/pygments) from 2.19.2 to 2.20.0. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.19.2...2.20.0) --- updated-dependencies: - dependency-name: pygments dependency-version: 2.20.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/backend/uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/backend/uv.lock b/ui/backend/uv.lock index bb53f3cee..ca349b617 100644 --- a/ui/backend/uv.lock +++ b/ui/backend/uv.lock @@ -1456,11 +1456,11 @@ wheels = [ [[package]] name = "pygments" -version = "2.19.2" +version = "2.20.0" 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" } +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/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { 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]] From 81edbe7b868e2d11e22ed4600d022e1536c5444a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:25 -0700 Subject: [PATCH 11/20] Bump path-to-regexp from 0.1.12 to 0.1.13 in /contrib/docs (#1533) Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 0.1.12 to 0.1.13. - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/v.0.1.13/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.12...v.0.1.13) --- updated-dependencies: - dependency-name: path-to-regexp dependency-version: 0.1.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- contrib/docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/docs/package-lock.json b/contrib/docs/package-lock.json index bccafeb6f..a3e2a3757 100644 --- a/contrib/docs/package-lock.json +++ b/contrib/docs/package-lock.json @@ -8553,9 +8553,9 @@ "license": "MIT" }, "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "license": "MIT" }, "node_modules/express/node_modules/range-parser": { From 1358b68dd5ef599253f4c493aa58ff8d95b7fda7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:28 -0700 Subject: [PATCH 12/20] Bump brace-expansion in /dev_tools/vscode_extension (#1530) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.13. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dev_tools/vscode_extension/package-lock.json | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dev_tools/vscode_extension/package-lock.json b/dev_tools/vscode_extension/package-lock.json index 81f7844f0..671cb94ae 100644 --- a/dev_tools/vscode_extension/package-lock.json +++ b/dev_tools/vscode_extension/package-lock.json @@ -3242,9 +3242,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -6575,9 +6575,9 @@ } }, "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -8149,9 +8149,9 @@ } }, "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "peer": true, @@ -8707,9 +8707,9 @@ } }, "node_modules/vscode-languageclient/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" From 86dfc8d4bb013319baef41de83c51fef134a7212 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:31 -0700 Subject: [PATCH 13/20] Bump requests from 2.32.5 to 2.33.0 in /ui/backend (#1528) Bumps [requests](https://github.com/psf/requests) from 2.32.5 to 2.33.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.32.5...v2.33.0) --- updated-dependencies: - dependency-name: requests dependency-version: 2.33.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/backend/uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/backend/uv.lock b/ui/backend/uv.lock index ca349b617..0958f164a 100644 --- a/ui/backend/uv.lock +++ b/ui/backend/uv.lock @@ -1486,7 +1486,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.5" +version = "2.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1494,9 +1494,9 @@ dependencies = [ { 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" } +sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" }, ] [[package]] From 0441b6ea559e1e229e0adef92fe5e00320a02e6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:34 -0700 Subject: [PATCH 14/20] Bump picomatch in /ui/frontend (#1526) Bumps and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together. Updates `picomatch` from 2.3.1 to 2.3.2 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) Updates `picomatch` from 4.0.3 to 4.0.4 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) --- updated-dependencies: - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect - dependency-name: picomatch dependency-version: 4.0.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/frontend/package-lock.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ui/frontend/package-lock.json b/ui/frontend/package-lock.json index 98fafdcf7..de5585c40 100644 --- a/ui/frontend/package-lock.json +++ b/ui/frontend/package-lock.json @@ -3636,9 +3636,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -7984,9 +7984,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -8488,9 +8488,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -9255,9 +9255,9 @@ } }, "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" From e7b91325b9f93d9af9ec5486f773eb349d574df7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:37 -0700 Subject: [PATCH 15/20] Bump yaml in /ui/frontend (#1525) Bumps and [yaml](https://github.com/eemeli/yaml). These dependencies needed to be updated together. Updates `yaml` from 2.8.2 to 2.8.3 - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3) Updates `yaml` from 1.10.2 to 1.10.3 - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.3 dependency-type: indirect - dependency-name: yaml dependency-version: 1.10.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/frontend/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/frontend/package-lock.json b/ui/frontend/package-lock.json index de5585c40..33a0d5b2e 100644 --- a/ui/frontend/package-lock.json +++ b/ui/frontend/package-lock.json @@ -4378,9 +4378,9 @@ } }, "node_modules/cosmiconfig/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "license": "ISC", "engines": { "node": ">= 6" @@ -11021,9 +11021,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "devOptional": true, "license": "ISC", "bin": { From f15b89aa780443e76eec0792e500037788dfae6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:16:39 -0700 Subject: [PATCH 16/20] Bump braces from 3.0.2 to 3.0.3 in /dev_tools/vscode_extension (#1522) Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-version: 3.0.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dev_tools/vscode_extension/package-lock.json | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dev_tools/vscode_extension/package-lock.json b/dev_tools/vscode_extension/package-lock.json index 671cb94ae..063793717 100644 --- a/dev_tools/vscode_extension/package-lock.json +++ b/dev_tools/vscode_extension/package-lock.json @@ -3253,12 +3253,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -4799,10 +4800,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5344,6 +5346,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -8464,6 +8467,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, From 14eba2882f105b9d12d23791573155ca102b5093 Mon Sep 17 00:00:00 2001 From: kartikeyamandhar Date: Sat, 4 Apr 2026 13:44:39 -0700 Subject: [PATCH 17/20] Address PR review comments: add Apache 2 headers, remove unused deps, fix image URLs, add .env.example --- .../neo4j_graph_rag/.env.example | 25 +++++++++++++++++++ .../LLM_Workflows/neo4j_graph_rag/.gitignore | 17 +++++++++++++ .../LLM_Workflows/neo4j_graph_rag/README.md | 6 ++--- .../neo4j_graph_rag/data/README.md | 19 ++++++++++++++ .../neo4j_graph_rag/data/data_refine.py | 18 +++++++++++++ .../neo4j_graph_rag/requirements.txt | 23 +++++++++++++---- 6 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 examples/LLM_Workflows/neo4j_graph_rag/.env.example diff --git a/examples/LLM_Workflows/neo4j_graph_rag/.env.example b/examples/LLM_Workflows/neo4j_graph_rag/.env.example new file mode 100644 index 000000000..3d70e233e --- /dev/null +++ b/examples/LLM_Workflows/neo4j_graph_rag/.env.example @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# OpenAI +OPENAI_API_KEY=your-openai-api-key-here + +# Neo4j +NEO4J_URI=bolt://localhost:7687 +NEO4J_USERNAME=neo4j +NEO4J_PASSWORD=password +NEO4J_DATABASE=neo4j diff --git a/examples/LLM_Workflows/neo4j_graph_rag/.gitignore b/examples/LLM_Workflows/neo4j_graph_rag/.gitignore index dd9ab9599..021d89f60 100644 --- a/examples/LLM_Workflows/neo4j_graph_rag/.gitignore +++ b/examples/LLM_Workflows/neo4j_graph_rag/.gitignore @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + # Environment .env diff --git a/examples/LLM_Workflows/neo4j_graph_rag/README.md b/examples/LLM_Workflows/neo4j_graph_rag/README.md index f1c4b277a..848d8d504 100644 --- a/examples/LLM_Workflows/neo4j_graph_rag/README.md +++ b/examples/LLM_Workflows/neo4j_graph_rag/README.md @@ -35,7 +35,7 @@ executing the pipeline. python run.py --mode ingest --visualise ``` -![Ingestion DAG](https://raw.githubusercontent.com/kartikeyamandhar/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/ingest_dag.png) +![Ingestion DAG](https://raw.githubusercontent.com/apache/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/ingest_dag.png) Raw TMDB JSON flows through parsing nodes into batched Neo4j writes. Hamilton automatically parallelises the four independent branches @@ -50,7 +50,7 @@ and `raw_credits` inputs. python run.py --mode embed --visualise ``` -![Embedding DAG](https://raw.githubusercontent.com/kartikeyamandhar/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/embed_dag.png) +![Embedding DAG](https://raw.githubusercontent.com/apache/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/embed_dag.png) Movie texts are fetched from Neo4j, batched through the OpenAI embeddings API, written back to Movie nodes, and a cosine vector index is created. @@ -63,7 +63,7 @@ API, written back to Movie nodes, and a cosine vector index is created. python run.py --mode query --visualise ``` -![RAG DAG](https://raw.githubusercontent.com/kartikeyamandhar/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/rag_dag.png) +![RAG DAG](https://raw.githubusercontent.com/apache/hamilton/examples/neo4j-graph-rag/examples/LLM_Workflows/neo4j_graph_rag/docs/images/rag_dag.png) The full 13-node RAG pipeline. Hamilton wires all dependencies from function signatures — no manual orchestration: diff --git a/examples/LLM_Workflows/neo4j_graph_rag/data/README.md b/examples/LLM_Workflows/neo4j_graph_rag/data/README.md index 790f19820..4b99bb6cd 100644 --- a/examples/LLM_Workflows/neo4j_graph_rag/data/README.md +++ b/examples/LLM_Workflows/neo4j_graph_rag/data/README.md @@ -1,3 +1,22 @@ + + # Data This example uses the [TMDB 5000 Movie Dataset](https://www.kaggle.com/datasets/tmdb/tmdb-movie-metadata) from Kaggle. diff --git a/examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py b/examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py index 5d1dc1884..d028de3f8 100644 --- a/examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py +++ b/examples/LLM_Workflows/neo4j_graph_rag/data/data_refine.py @@ -1,3 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + import pandas as pd, json movies = pd.read_csv("examples/LLM_Workflows/neo4j_graph_rag/data/tmdb_5000_movies.csv") diff --git a/examples/LLM_Workflows/neo4j_graph_rag/requirements.txt b/examples/LLM_Workflows/neo4j_graph_rag/requirements.txt index 8c44a1add..e1e08da02 100644 --- a/examples/LLM_Workflows/neo4j_graph_rag/requirements.txt +++ b/examples/LLM_Workflows/neo4j_graph_rag/requirements.txt @@ -1,10 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + sf-hamilton>=1.73.0 neo4j>=5.18.0 -llama-index>=0.10.0 -llama-index-graph-stores-neo4j>=0.2.0 -llama-index-llms-openai>=0.1.0 -llama-index-embeddings-openai>=0.1.0 openai>=1.30.0 pandas>=2.0.0 python-dotenv>=1.0.0 -tqdm>=4.66.0 \ No newline at end of file +tqdm>=4.66.0 From deb190d5f17f205655ab8fe9c06c89b033058c3c Mon Sep 17 00:00:00 2001 From: Stefan Krawczyk Date: Fri, 3 Apr 2026 20:53:19 -0700 Subject: [PATCH 18/20] Various build & release fixes (#1529) * Fix release helper: use --no-use-vcs flag and restore twine check - Switch from FLIT_USE_VCS=0 env var to --no-use-vcs CLI flag (flit 3.12.0 does not respect the env var) - Restore twine to prerequisites check - Restore verify_wheel_with_twine call before signing Add release tooling: verification scripts, build fixes, and docs - Add verify_apache_artifacts.py for GPG signature, checksum, and license verification - Add scripts/README.md with build, release, and voter verification instructions (uv-based) - Add .rat-excludes for Apache RAT license header checks - Add verify_ui_build.sh with Apache license header - Fix release helper: add verify_wheel_with_twine function, --dry-run flag, remove -incubating suffix from wheel (invalid per PEP 427), clean up original flit artifacts after creating incubating copies - Add tests, plugin_tests, and representative examples to flit sdist includes * Adds uv run to examples adds uv run to examples * Address PR review feedback - Fix typo: singed -> signed in release helper - Use list unpacking instead of concatenation for files_to_upload - Validate exactly 1 tarball/wheel from glob (not just non-empty) - Add release dependency group (flit, twine) to pyproject.toml - Update README to use uv sync --group release and uv sync --group test - Fix grammar and add --clean flag to uv venv in README - Add uv run prefix to verify_apache_artifacts.py epilog examples - Run ruff format on verify_apache_artifacts.py * Exclude databackend from license check in pre-commit --- .pre-commit-config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9ea73c3ee..6a29c848b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -70,7 +70,8 @@ repos: (?x) ^\.github/| ^docs/| - ^examples/ + ^examples/| + ^hamilton/experimental/databackend.py args: - --comment-style - "|#|" From 894ba2e70e289221089741787428921fad11b1d7 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Sat, 4 Apr 2026 06:06:17 +0200 Subject: [PATCH 19/20] Remove license comments from databackend.py (#1535) * Remove license comments from databackend.py Removed Apache License comments from the file. * Fix pre-commit-config --------- Co-authored-by: Stefan Krawczyk --- .pre-commit-config.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6a29c848b..9ea73c3ee 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -70,8 +70,7 @@ repos: (?x) ^\.github/| ^docs/| - ^examples/| - ^hamilton/experimental/databackend.py + ^examples/ args: - --comment-style - "|#|" From ca523a11b4700e076d92b959558fbe6e89d6afac Mon Sep 17 00:00:00 2001 From: kartikeyamandhar Date: Sun, 5 Apr 2026 15:55:20 -0700 Subject: [PATCH 20/20] Add Neo4j GraphRAG example to ecosystem page --- docs/ecosystem/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ecosystem/index.md b/docs/ecosystem/index.md index 789dcee6d..d13f48c5f 100644 --- a/docs/ecosystem/index.md +++ b/docs/ecosystem/index.md @@ -148,6 +148,7 @@ Persist and cache your data: | **Slack** | Notifications and integrations | [Examples](https://github.com/apache/hamilton/tree/main/examples/slack) \| [Lifecycle Hook](../reference/lifecycle-hooks/SlackNotifierHook.rst) | | **GeoPandas** | Geospatial data analysis | [Type extension](https://github.com/apache/hamilton/blob/main/hamilton/plugins/geopandas_extensions.py) for GeoDataFrame support | | **YAML** | Configuration management | [IO Adapters](../reference/io/available-data-adapters.rst) | +| **Neo4j** | Knowledge graph RAG | [Examples](https://github.com/apache/hamilton/tree/main/examples/LLM_Workflows/neo4j_graph_rag) | ---