diff --git a/README.md b/README.md index f819ff7..7ea5032 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ cd cadence-python-client ```bash # macOS brew install protobuf@29 - + # Linux/Other # Install protobuf 29.x via your package manager ``` @@ -35,7 +35,7 @@ cd cadence-python-client ```bash # macOS brew install uv - + # Linux/Other curl -LsSf https://astral.sh/uv/install.sh | sh source $HOME/.local/bin/env # Add to your shell profile for persistence @@ -59,6 +59,7 @@ cd cadence-python-client Run the generation script: ```bash # Using uv (recommended) +uv sync --extra dev uv run python scripts/generate_proto.py # Or using traditional Python diff --git a/cadence/api/__init__.py b/cadence/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/cadence/api/v1/__init__.py b/cadence/api/v1/__init__.py index a243798..700288a 100644 --- a/cadence/api/v1/__init__.py +++ b/cadence/api/v1/__init__.py @@ -1,92 +1,92 @@ # Auto-generated __init__.py file -# Import all generated protobuf and gRPC modules +# Import all generated protobuf modules from . import common_pb2 -from . import decision_pb2 -from . import domain_pb2 -from . import error_pb2 -from . import history_pb2 -from . import query_pb2 -from . import service_domain_pb2 -from . import service_meta_pb2 -from . import service_visibility_pb2 -from . import service_worker_pb2 -from . import service_workflow_pb2 -from . import tasklist_pb2 -from . import visibility_pb2 -from . import workflow_pb2 from . import common_pb2_grpc +from . import decision_pb2 from . import decision_pb2_grpc +from . import domain_pb2 from . import domain_pb2_grpc +from . import error_pb2 from . import error_pb2_grpc +from . import history_pb2 from . import history_pb2_grpc +from . import query_pb2 from . import query_pb2_grpc +from . import service_domain_pb2 from . import service_domain_pb2_grpc +from . import service_meta_pb2 from . import service_meta_pb2_grpc +from . import service_visibility_pb2 from . import service_visibility_pb2_grpc +from . import service_worker_pb2 from . import service_worker_pb2_grpc +from . import service_workflow_pb2 from . import service_workflow_pb2_grpc +from . import tasklist_pb2 from . import tasklist_pb2_grpc +from . import visibility_pb2 from . import visibility_pb2_grpc +from . import workflow_pb2 from . import workflow_pb2_grpc # Create cleaner aliases for easier imports common = common_pb2 -decision = decision_pb2 -domain = domain_pb2 -error = error_pb2 -history = history_pb2 -query = query_pb2 -service_domain = service_domain_pb2 -service_meta = service_meta_pb2 -service_visibility = service_visibility_pb2 -service_worker = service_worker_pb2 -service_workflow = service_workflow_pb2 -tasklist = tasklist_pb2 -visibility = visibility_pb2 -workflow = workflow_pb2 common_grpc = common_pb2_grpc +decision = decision_pb2 decision_grpc = decision_pb2_grpc +domain = domain_pb2 domain_grpc = domain_pb2_grpc +error = error_pb2 error_grpc = error_pb2_grpc +history = history_pb2 history_grpc = history_pb2_grpc +query = query_pb2 query_grpc = query_pb2_grpc +service_domain = service_domain_pb2 service_domain_grpc = service_domain_pb2_grpc +service_meta = service_meta_pb2 service_meta_grpc = service_meta_pb2_grpc +service_visibility = service_visibility_pb2 service_visibility_grpc = service_visibility_pb2_grpc +service_worker = service_worker_pb2 service_worker_grpc = service_worker_pb2_grpc +service_workflow = service_workflow_pb2 service_workflow_grpc = service_workflow_pb2_grpc +tasklist = tasklist_pb2 tasklist_grpc = tasklist_pb2_grpc +visibility = visibility_pb2 visibility_grpc = visibility_pb2_grpc +workflow = workflow_pb2 workflow_grpc = workflow_pb2_grpc -# Only expose clean module names +# Only expose clean module names (no _pb2) __all__ = [ 'common', - 'decision', - 'domain', - 'error', - 'history', - 'query', - 'service_domain', - 'service_meta', - 'service_visibility', - 'service_worker', - 'service_workflow', - 'tasklist', - 'visibility', - 'workflow', 'common_grpc', + 'decision', 'decision_grpc', + 'domain', 'domain_grpc', + 'error', 'error_grpc', + 'history', 'history_grpc', + 'query', 'query_grpc', + 'service_domain', 'service_domain_grpc', + 'service_meta', 'service_meta_grpc', + 'service_visibility', 'service_visibility_grpc', + 'service_worker', 'service_worker_grpc', + 'service_workflow', 'service_workflow_grpc', + 'tasklist', 'tasklist_grpc', + 'visibility', 'visibility_grpc', + 'workflow', 'workflow_grpc', ] diff --git a/cadence/api/v1/common_pb2.py b/cadence/api/v1/common_pb2.py index 03f7e46..b7e3f12 100644 --- a/cadence/api/v1/common_pb2.py +++ b/cadence/api/v1/common_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/common.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/common.proto' ) diff --git a/cadence/api/v1/decision_pb2.py b/cadence/api/v1/decision_pb2.py index 3e8f815..36a1bf0 100644 --- a/cadence/api/v1/decision_pb2.py +++ b/cadence/api/v1/decision_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/decision.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/decision.proto' ) diff --git a/cadence/api/v1/domain_pb2.py b/cadence/api/v1/domain_pb2.py index 811282a..bc73e08 100644 --- a/cadence/api/v1/domain_pb2.py +++ b/cadence/api/v1/domain_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/domain.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/domain.proto' ) diff --git a/cadence/api/v1/error_pb2.py b/cadence/api/v1/error_pb2.py index e915ea0..09fdd1c 100644 --- a/cadence/api/v1/error_pb2.py +++ b/cadence/api/v1/error_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/error.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/error.proto' ) diff --git a/cadence/api/v1/history_pb2.py b/cadence/api/v1/history_pb2.py index 1c61ab4..e1427ea 100644 --- a/cadence/api/v1/history_pb2.py +++ b/cadence/api/v1/history_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/history.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/history.proto' ) diff --git a/cadence/api/v1/query_pb2.py b/cadence/api/v1/query_pb2.py index 34d36ba..8d492e0 100644 --- a/cadence/api/v1/query_pb2.py +++ b/cadence/api/v1/query_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/query.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/query.proto' ) diff --git a/cadence/api/v1/service_domain_pb2.py b/cadence/api/v1/service_domain_pb2.py index 6262755..50679a4 100644 --- a/cadence/api/v1/service_domain_pb2.py +++ b/cadence/api/v1/service_domain_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/service_domain.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/service_domain.proto' ) diff --git a/cadence/api/v1/service_meta_pb2.py b/cadence/api/v1/service_meta_pb2.py index 4229a74..2103aff 100644 --- a/cadence/api/v1/service_meta_pb2.py +++ b/cadence/api/v1/service_meta_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/service_meta.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/service_meta.proto' ) diff --git a/cadence/api/v1/service_visibility_pb2.py b/cadence/api/v1/service_visibility_pb2.py index ad18302..828a23d 100644 --- a/cadence/api/v1/service_visibility_pb2.py +++ b/cadence/api/v1/service_visibility_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/service_visibility.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/service_visibility.proto' ) diff --git a/cadence/api/v1/service_worker_pb2.py b/cadence/api/v1/service_worker_pb2.py index 1fe34a3..106300b 100644 --- a/cadence/api/v1/service_worker_pb2.py +++ b/cadence/api/v1/service_worker_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/service_worker.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/service_worker.proto' ) diff --git a/cadence/api/v1/service_workflow_pb2.py b/cadence/api/v1/service_workflow_pb2.py index a6bc922..6b4d026 100644 --- a/cadence/api/v1/service_workflow_pb2.py +++ b/cadence/api/v1/service_workflow_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/service_workflow.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/service_workflow.proto' ) diff --git a/cadence/api/v1/tasklist_pb2.py b/cadence/api/v1/tasklist_pb2.py index e4c5051..96db2a5 100644 --- a/cadence/api/v1/tasklist_pb2.py +++ b/cadence/api/v1/tasklist_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/tasklist.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/tasklist.proto' ) diff --git a/cadence/api/v1/visibility_pb2.py b/cadence/api/v1/visibility_pb2.py index 2f92971..7fba6d8 100644 --- a/cadence/api/v1/visibility_pb2.py +++ b/cadence/api/v1/visibility_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/visibility.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/visibility.proto' ) diff --git a/cadence/api/v1/workflow_pb2.py b/cadence/api/v1/workflow_pb2.py index 8a55a8b..9794605 100644 --- a/cadence/api/v1/workflow_pb2.py +++ b/cadence/api/v1/workflow_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: cadence/api/v1/workflow.proto -# Protobuf Python Version: 5.29.1 +# Protobuf Python Version: 5.29.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 5, 29, - 1, + 0, '', 'cadence/api/v1/workflow.proto' ) diff --git a/pyproject.toml b/pyproject.toml index c154d3e..de3ecc2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,8 +26,7 @@ classifiers = [ ] requires-python = ">=3.11,<3.14" dependencies = [ - "grpcio>=1.50.0", - "grpcio-tools>=1.50.0", + "grpcio==1.71.2", "msgspec>=0.19.0", "protobuf==5.29.1", "typing-extensions>=4.0.0", @@ -35,6 +34,7 @@ dependencies = [ [project.optional-dependencies] dev = [ + "grpcio-tools==1.71.2", "pytest>=8.4.1", "pytest-cov>=4.0.0", "pytest-asyncio>=0.21.0", diff --git a/scripts/generate_proto.py b/scripts/generate_proto.py index 096392e..e50efd5 100644 --- a/scripts/generate_proto.py +++ b/scripts/generate_proto.py @@ -6,203 +6,29 @@ import subprocess import sys -import os from pathlib import Path import shutil -import platform -import urllib.request -import zipfile +import runpy - -def check_grpc_tools(): - """Check if grpc_tools is installed, install if not.""" - try: - print("✓ grpc_tools is already installed") - return True - except ImportError: - print("Installing grpc_tools...") - try: - subprocess.run(["uv", "pip", "install", "grpcio-tools"], - check=True, capture_output=True, text=True) - print("✓ grpc_tools installed successfully") - return True - except subprocess.CalledProcessError as e: - print(f"✗ Failed to install grpc_tools: {e}") - return False - - -def find_grpc_python_plugin(): - """Find the grpc_python_plugin binary.""" - try: - # Try to find it in the current Python environment using uv - result = subprocess.run(["uv", "run", "python", "-m", "grpc_tools.protoc", "--help"], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - # The plugin is available through grpc_tools.protoc - return "grpc_tools.protoc" - except (subprocess.TimeoutExpired, FileNotFoundError): - pass - - # Try to find it as a standalone binary +def get_project_root() -> Path: try: - result = subprocess.run(["grpc_python_plugin", "--help"], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - return "grpc_python_plugin" - except (subprocess.TimeoutExpired, FileNotFoundError): - pass - - return None - - -def download_protoc_29_1(project_root: Path) -> str: - """Download protoc 29.1 from GitHub releases to .bin directory like the cadence-idl Makefile.""" - bin_dir = project_root / ".bin" - bin_dir.mkdir(exist_ok=True) - - # Determine OS and architecture - os_name = platform.system().lower() - arch = platform.machine().lower() - - # Normalize architecture names for protobuf releases (like the Makefile) - if arch in ['arm64', 'aarch64']: - arch = 'aarch_64' - elif arch == 'x86_64': - arch = 'x86_64' - - # Normalize OS names - if os_name == 'darwin': - os_name = 'osx' - elif os_name == 'linux': - os_name = 'linux' - elif os_name == 'windows': - os_name = 'windows' - - protoc_version = "29.1" - protoc_bin = bin_dir / f"protoc-{protoc_version}" - - # Check if already downloaded - if protoc_bin.exists(): - try: - result = subprocess.run([str(protoc_bin), "--version"], - capture_output=True, text=True, timeout=5) - if result.returncode == 0 and "29.1" in result.stdout: - print(f"Using existing .bin protoc 29.1: {result.stdout.strip()}") - return str(protoc_bin) - except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError): - pass - - # Download URL (same as Makefile) - url = f"https://github.com/protocolbuffers/protobuf/releases/download/v{protoc_version}/protoc-{protoc_version}-{os_name}-{arch}.zip" - zip_path = bin_dir / "protoc.zip" - unzip_dir = bin_dir / f"protoc-{protoc_version}-zip" - - print(f"Downloading protoc {protoc_version} to .bin directory from {url}") - - try: - # Download - urllib.request.urlretrieve(url, zip_path) - - # Clean up any existing unzip directory - if unzip_dir.exists(): - shutil.rmtree(unzip_dir) - - # Unzip - with zipfile.ZipFile(zip_path, 'r') as zip_ref: - zip_ref.extractall(unzip_dir) - - # Copy protoc binary to standard location - source_protoc = unzip_dir / "bin" / "protoc" - if source_protoc.exists(): - shutil.copy2(source_protoc, protoc_bin) - protoc_bin.chmod(0o755) # Make executable - - # Also copy the include directory with Google protobuf standard library files - source_include = unzip_dir / "include" - if source_include.exists(): - target_include = project_root / ".bin" / "include" - if target_include.exists(): - shutil.rmtree(target_include) - shutil.copytree(source_include, target_include) - print(f"✓ Copied protobuf include files to {target_include}") - - # Clean up - shutil.rmtree(unzip_dir) - zip_path.unlink() - - print(f"Successfully downloaded and installed protoc {protoc_version} to .bin directory") - return str(protoc_bin) - else: - raise FileNotFoundError(f"protoc binary not found in {source_protoc}") - - except Exception as e: - print(f"Failed to download protoc 29.1: {e}") - # Clean up on failure - if zip_path.exists(): - zip_path.unlink() - if unzip_dir.exists(): - shutil.rmtree(unzip_dir) - raise - - -def find_protoc() -> str: - """Find the protoc binary, preferring .bin/protoc-29.1, then download it if not available.""" - script_dir = Path(__file__).parent - project_root = script_dir.parent - - # First, check for protoc-29.1 in .bin directory (preferred) - bin_protoc = project_root / ".bin" / "protoc-29.1" - if bin_protoc.exists(): - try: - result = subprocess.run([str(bin_protoc), "--version"], - capture_output=True, text=True, timeout=5) - if result.returncode == 0 and "29.1" in result.stdout: - print(f"Using .bin protoc-29.1: {result.stdout.strip()}") - return str(bin_protoc) - except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError) as e: - print(f"Warning: .bin protoc-29.1 failed: {e}") - - # Download protoc 29.1 to .bin directory if not available - try: - protoc_29_1_path = download_protoc_29_1(project_root) - return protoc_29_1_path - except Exception as e: - print(f"Error: Could not download protoc 29.1: {e}") - raise RuntimeError( - f"Failed to download protoc 29.1 to .bin directory: {e}\n" - "Please check your internet connection and try again." + return Path( + subprocess.check_output( + ["git", "rev-parse", "--show-toplevel"], text=True + ).strip() ) - - -def find_proto_files(proto_dir: Path) -> list[Path]: - """Find all .proto files in the given directory, excluding admin files.""" - proto_files = [] - for proto_file in proto_dir.rglob("*.proto"): - # Skip admin proto files - if "admin" in str(proto_file): - continue - proto_files.append(proto_file) - return sorted(proto_files) - - -def create_init_files(output_dir: Path) -> None: - """Create __init__.py files for all subdirectories.""" - for subdir in output_dir.rglob("*"): - if subdir.is_dir(): - init_file = subdir / "__init__.py" - if not init_file.exists(): - init_file.touch() - print(f" ✓ Created {init_file}") - + except Exception as e: + raise RuntimeError("Error: Could not determine project root from git:", e) def generate_init_file(output_dir: Path) -> None: """Generate the __init__.py file for cadence/api/v1 with clean imports.""" - v1_dir = output_dir / "api" / "v1" + v1_dir = output_dir / "cadence" / "api" / "v1" init_file = v1_dir / "__init__.py" + init_file.touch() # Find all _pb2.py files in the v1 directory pb2_files = [] - for file in v1_dir.glob("*_pb2.py"): + for file in v1_dir.glob("*_pb2*.py"): module_name = file.stem # e.g., "common_pb2" -> "common_pb2" clean_name = module_name.replace("_pb2", "") # e.g., "common_pb2" -> "common" pb2_files.append((module_name, clean_name)) @@ -239,118 +65,18 @@ def generate_init_file(output_dir: Path) -> None: print(f" ✓ Generated {init_file} with {len(pb2_files)} modules") - -def find_protobuf_include(project_root: Path) -> str: - """Find the protobuf include directory, preferring downloaded protoc 29.1, then system installations.""" - # First, check if we have downloaded protoc 29.1 and use its include directory - protoc_29_1_bin = project_root / ".bin" / "protoc-29.1" - if protoc_29_1_bin.exists(): - # The downloaded protoc includes the well-known types in the zip - # Check for the include directory in .bin first - bin_include = project_root / ".bin" / "include" - if bin_include.exists(): - print(f"Using .bin protobuf include directory: {bin_include}") - return str(bin_include) - - # Fallback to local include directory - local_include = project_root / "include" - if local_include.exists(): - print(f"Using local include directory: {local_include}") - return str(local_include) - - # Check if we're on macOS (using brew) - if platform.system().lower() == 'darwin': - try: - # Try to find main brew protobuf installation (version 29.3) - result = subprocess.run(["brew", "--prefix", "protobuf"], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - brew_prefix = result.stdout.strip() - include_path = f"{brew_prefix}/include" - if os.path.exists(include_path): - print(f"Using main protobuf include: {include_path}") - return include_path - except (subprocess.TimeoutExpired, FileNotFoundError): - pass - - # Check protobuf@29 second (version 29.4) - protobuf_29_include = "/opt/homebrew/opt/protobuf@29/include" - if os.path.exists(protobuf_29_include): - print(f"Using protobuf@29 include: {protobuf_29_include}") - return protobuf_29_include - - # Fallback to common brew location - common_paths = [ - "/opt/homebrew/include", - "/usr/local/include", - "/opt/homebrew/Cellar/protobuf/*/include" - ] - - for path_pattern in common_paths: - if "*" in path_pattern: - # Handle wildcard pattern - import glob - matches = glob.glob(path_pattern) - if matches: - # Use the latest version - latest = sorted(matches)[-1] - if os.path.exists(latest): - print(f"Using brew protobuf include: {latest}") - return latest - else: - if os.path.exists(path_pattern): - print(f"Using brew protobuf include: {path_pattern}") - return path_pattern - - # Linux paths - elif platform.system().lower() == 'linux': - # Common Linux protobuf include paths - linux_paths = [ - "/usr/include", - "/usr/local/include", - "/opt/protobuf/include", - "/usr/share/protobuf/include" - ] - - for path in linux_paths: - if os.path.exists(path): - print(f"Using Linux protobuf include: {path}") - return path - - return None - - def setup_temp_proto_structure(proto_dir: Path, temp_dir: Path) -> None: """Create a temporary directory with proto files in the proper structure for cadence.api.v1 imports.""" print("Setting up temporary proto structure...") - # Find all proto files (excluding admin) - proto_files = find_proto_files(proto_dir) - - if not proto_files: - print("No .proto files found!") - return - - print(f"Found {len(proto_files)} .proto files (excluding admin):") - for proto_file in proto_files: - print(f" - {proto_file}") + proto_file_dir = proto_dir / "uber" / "cadence" / "api" / "v1" + output_dir = temp_dir / "cadence" / "api" / "v1" - # Copy proto files to temp directory with proper structure - for proto_file in proto_files: - # Get relative path from proto directory - rel_path = proto_file.relative_to(proto_dir) - - # Create target path in temp directory - # We want to transform: uber/cadence/api/v1/file.proto -> cadence/api/v1/file.proto - parts = list(rel_path.parts) - - # Remove 'uber' from the path to get cadence.api.v1 structure - if parts[0] == 'uber': - parts = parts[1:] # Remove 'uber' - - target_path = temp_dir / Path(*parts) - target_path.parent.mkdir(parents=True, exist_ok=True) + # Create the cadence/api/v1 directory structure in temp_dir + output_dir.mkdir(parents=True, exist_ok=True) + # Copy all proto files from proto_dir to temp_dir + for proto_file in proto_file_dir.glob("*.proto"): # Copy the proto file and update import statements with open(proto_file, 'r') as src_file: content = src_file.read() @@ -360,249 +86,63 @@ def setup_temp_proto_structure(proto_dir: Path, temp_dir: Path) -> None: updated_content = content.replace('import "uber/cadence/api/v1/', 'import "cadence/api/v1/') # Write the updated content to the target file - with open(target_path, 'w') as dst_file: + with open(output_dir / proto_file.name, 'w') as dst_file: dst_file.write(updated_content) - print(f" ✓ Copied and updated {rel_path} -> {target_path}") + print(f" ✓ Copied and updated {proto_file.name}") +def delete_temp_dir(temp_dir: Path): + if temp_dir.exists(): + shutil.rmtree(temp_dir) + print(f"Deleted temp directory: {temp_dir}") -def generate_protobuf_files(temp_proto_dir: Path, output_dir: Path, project_root: Path) -> None: - """Generate Python protobuf files and gRPC code from .proto files in temp directory.""" - proto_files = list(temp_proto_dir.rglob("*.proto")) +def generate_protobuf_files(temp_dir: Path, gen_dir: Path) -> None: + # Find all .proto files in the cadence/api/v1 directory + proto_files = list((temp_dir / "cadence/api/v1").glob("*.proto")) if not proto_files: - print("No .proto files found in temp directory!") - return + print("No .proto files found in temp_dir/cadence/api/v1/") + delete_temp_dir(temp_dir) + sys.exit(1) - print(f"Generating Python files from {len(proto_files)} .proto files...") + # Convert Path objects to strings for sys.argv + proto_file_paths = [str(f) for f in proto_files] - # Create output directory if it doesn't exist - output_dir.mkdir(parents=True, exist_ok=True) + # Save original argv and set up new argv for grpc_tools.protoc + original_argv = sys.argv + sys.argv = [ + "grpc_tools.protoc", + "--proto_path", str(temp_dir), + "--python_out", str(gen_dir), + "--pyi_out", str(gen_dir), + "--grpc_python_out", str(gen_dir) + ] + proto_file_paths - # Find protoc binary - always use the downloaded protoc 29.1 - protoc_path = find_protoc() - print(f"Using protoc: {protoc_path}") - - # Check for gRPC tools - if not check_grpc_tools(): - print("Warning: grpc_tools not available, skipping gRPC code generation") - grpc_plugin = None - else: - grpc_plugin = find_grpc_python_plugin() - if grpc_plugin: - print(f"✓ Found gRPC plugin: {grpc_plugin}") + try: + runpy.run_module("grpc_tools.protoc", run_name="__main__", alter_sys=True) + print(f"Successfully generated protobuf files using runpy for {len(proto_files)} files") + except SystemExit as e: + if e.code == 0: + print(f"Successfully generated protobuf files using runpy for {len(proto_files)} files") else: - print("Warning: grpc_python_plugin not found, skipping gRPC code generation") - - # Generate Python files for each proto file - for proto_file in proto_files: - # Get relative path from temp proto directory - rel_path = proto_file.relative_to(temp_proto_dir) - - # Build command with appropriate include paths - cmd = [ - protoc_path, - f"--python_out={output_dir}", - f"--pyi_out={output_dir}", - f"--proto_path={temp_proto_dir}", - ] - - cmd.append(f"--proto_path={project_root}/include") - - cmd.append(str(proto_file)) - - try: - subprocess.run(cmd, check=True, capture_output=True, text=True) - print(f" ✓ Generated .py and .pyi files for {rel_path}") - except subprocess.CalledProcessError as e: - print(f" ✗ Failed to generate .py and .pyi files for {rel_path}: {e}") - print(f" stderr: {e.stderr}") - continue - - # Add gRPC generation if plugin is available - if grpc_plugin and grpc_plugin == "grpc_tools.protoc": - # For grpc_tools.protoc, only generate gRPC files (not _pb2.py) - grpc_cmd = [ - "uv", "run", "python", "-m", "grpc_tools.protoc", - f"--grpc_python_out={output_dir}", - f"--proto_path={temp_proto_dir}", - ] - - grpc_cmd.append(f"--proto_path={project_root}/include") - - grpc_cmd.append(str(proto_file)) - - try: - subprocess.run(grpc_cmd, check=True, capture_output=True, text=True) - print(f" ✓ Generated gRPC files for {rel_path}") - except subprocess.CalledProcessError as e: - print(f" ✗ Failed to generate gRPC files for {rel_path}: {e}") - print(f" stderr: {e.stderr}") - - elif grpc_plugin and grpc_plugin != "grpc_tools.protoc": - # Use standalone protoc with grpc_python_plugin - grpc_cmd = [ - protoc_path, - f"--grpc_python_out={output_dir}", - f"--proto_path={temp_proto_dir}", - ] - - grpc_cmd.append(f"--proto_path={project_root}/include") - - grpc_cmd.append(str(proto_file)) - - try: - subprocess.run(grpc_cmd, check=True, capture_output=True, text=True) - print(f" ✓ Generated gRPC files for {rel_path}") - except subprocess.CalledProcessError as e: - print(f" ✗ Failed to generate gRPC files for {rel_path}: {e}") - print(f" stderr: {e.stderr}") - - # Move files from nested structure to correct structure - print("Moving files to correct structure...") - nested_cadence_dir = output_dir / "cadence" - if nested_cadence_dir.exists(): - # Move all contents from cadence/cadence/api/v1/ to cadence/api/v1/ - nested_api_dir = nested_cadence_dir / "api" - if nested_api_dir.exists(): - target_api_dir = output_dir / "api" - target_api_dir.mkdir(parents=True, exist_ok=True) - - # Move api/v1 directory - nested_v1_dir = nested_api_dir / "v1" - target_v1_dir = target_api_dir / "v1" - - if nested_v1_dir.exists(): - # Remove target if it exists - if target_v1_dir.exists(): - shutil.rmtree(target_v1_dir) - - # Move the v1 directory - shutil.move(str(nested_v1_dir), str(target_v1_dir)) - print(" ✓ Moved api/v1 directory to correct location") - - # Move api/__init__.py if it exists - nested_init = nested_api_dir / "__init__.py" - target_init = target_api_dir / "__init__.py" - if nested_init.exists(): - shutil.move(str(nested_init), str(target_init)) - print(" ✓ Moved api/__init__.py to correct location") - - # Remove the nested cadence directory - shutil.rmtree(nested_cadence_dir) - print(" ✓ Cleaned up nested cadence directory") - - -def generate_grpc_init_file(output_dir: Path) -> None: - """Generate the __init__.py file for cadence/api/v1 with gRPC imports.""" - v1_dir = output_dir / "api" / "v1" - init_file = v1_dir / "__init__.py" - - # Find all _pb2.py and _pb2_grpc.py files in the v1 directory - pb2_files = [] - grpc_files = [] - - for file in v1_dir.glob("*_pb2.py"): - module_name = file.stem # e.g., "common_pb2" -> "common_pb2" - clean_name = module_name.replace("_pb2", "") # e.g., "common_pb2" -> "common" - pb2_files.append((module_name, clean_name)) - - for file in v1_dir.glob("*_pb2_grpc.py"): - module_name = file.stem # e.g., "service_workflow_pb2_grpc" -> "service_workflow_pb2_grpc" - clean_name = module_name.replace("_pb2_grpc", "_grpc") # e.g., "service_workflow_pb2_grpc" -> "service_workflow_grpc" - grpc_files.append((module_name, clean_name)) - - # Sort for consistent ordering - pb2_files.sort() - grpc_files.sort() - - # Generate the __init__.py content - content = "# Auto-generated __init__.py file\n" - content += "# Import all generated protobuf and gRPC modules\n" - - # Add protobuf imports - for module_name, clean_name in pb2_files: - content += f"from . import {module_name}\n" - - # Add gRPC imports - for module_name, clean_name in grpc_files: - content += f"from . import {module_name}\n" - - content += "\n# Create cleaner aliases for easier imports\n" - - # Add protobuf aliases - for module_name, clean_name in pb2_files: - content += f"{clean_name} = {module_name}\n" - - # Add gRPC aliases - for module_name, clean_name in grpc_files: - content += f"{clean_name} = {module_name}\n" - - content += "\n# Only expose clean module names\n" - content += "__all__ = [\n" - - # Add __all__ list - for module_name, clean_name in pb2_files: - content += f" '{clean_name}',\n" - for module_name, clean_name in grpc_files: - content += f" '{clean_name}',\n" - - content += "]\n" - - # Write the file - with open(init_file, 'w') as f: - f.write(content) - - print(f" ✓ Generated {init_file} with {len(pb2_files)} protobuf and {len(grpc_files)} gRPC modules") - + print("Error running grpc_tools.protoc via runpy {}", e) + raise e + finally: + # Restore original argv + sys.argv = original_argv def main(): - """Main function.""" - # Get the script directory - script_dir = Path(__file__).parent - project_root = script_dir.parent + project_root = get_project_root() - # Define paths proto_dir = project_root / "idls" / "proto" - output_dir = project_root / "cadence" # This will be the cadence folder directly temp_dir = project_root / ".temp_proto" + gen_dir = project_root - print(f"Proto directory: {proto_dir}") - print(f"Output directory: {output_dir}") - print(f"Temp directory: {temp_dir}") - - # Check if proto directory exists - if not proto_dir.exists(): - print(f"Error: Proto directory not found: {proto_dir}") - sys.exit(1) - - # Clean up temp directory if it exists - if temp_dir.exists(): - shutil.rmtree(temp_dir) - - try: - # Step 1: Create temp directory and copy proto files in proper structure - temp_dir.mkdir(exist_ok=True) - setup_temp_proto_structure(proto_dir, temp_dir) - - # Step 2: Generate Python files in the cadence directory - generate_protobuf_files(temp_dir, output_dir, project_root) - - # Step 3: Create __init__.py files for all generated directories - create_init_files(output_dir) - generate_grpc_init_file(output_dir) - - print(f"\nProtobuf and gRPC generation complete. Files generated in {output_dir}") - print("Files can now be imported as:") - print(" - cadence.api.v1.workflow (protobuf messages)") - print(" - cadence.api.v1.service_workflow_grpc (gRPC services)") - - finally: - # Step 4: Clean up temp directory - if temp_dir.exists(): - shutil.rmtree(temp_dir) - print(f"Cleaned up temp directory: {temp_dir}") + setup_temp_proto_structure(proto_dir, temp_dir) + generate_protobuf_files(temp_dir, gen_dir) + generate_init_file(gen_dir) + delete_temp_dir(temp_dir) if __name__ == "__main__": main() diff --git a/uv.lock b/uv.lock index fe3f9e0..cf85812 100644 --- a/uv.lock +++ b/uv.lock @@ -153,7 +153,6 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "grpcio" }, - { name = "grpcio-tools" }, { name = "msgspec" }, { name = "protobuf" }, { name = "typing-extensions" }, @@ -163,6 +162,7 @@ dependencies = [ dev = [ { name = "black" }, { name = "flake8" }, + { name = "grpcio-tools" }, { name = "isort" }, { name = "mypy" }, { name = "pre-commit" }, @@ -185,8 +185,8 @@ requires-dist = [ { name = "aiohttp", marker = "extra == 'examples'", specifier = ">=3.8.0" }, { name = "black", marker = "extra == 'dev'", specifier = ">=23.0.0" }, { name = "flake8", marker = "extra == 'dev'", specifier = ">=6.0.0" }, - { name = "grpcio", specifier = ">=1.50.0" }, - { name = "grpcio-tools", specifier = ">=1.50.0" }, + { name = "grpcio", specifier = "==1.71.2" }, + { name = "grpcio-tools", marker = "extra == 'dev'", specifier = "==1.71.2" }, { name = "isort", marker = "extra == 'dev'", specifier = ">=5.12.0" }, { name = "msgspec", specifier = ">=0.19.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.0.0" }, @@ -468,40 +468,40 @@ wheels = [ [[package]] name = "grpcio" -version = "1.74.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/b4/35feb8f7cab7239c5b94bd2db71abb3d6adb5f335ad8f131abb6060840b6/grpcio-1.74.0.tar.gz", hash = "sha256:80d1f4fbb35b0742d3e3d3bb654b7381cd5f015f8497279a1e9c21ba623e01b1", size = 12756048, upload-time = "2025-07-24T18:54:23.039Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/77/b2f06db9f240a5abeddd23a0e49eae2b6ac54d85f0e5267784ce02269c3b/grpcio-1.74.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:69e1a8180868a2576f02356565f16635b99088da7df3d45aaa7e24e73a054e31", size = 5487368, upload-time = "2025-07-24T18:53:03.548Z" }, - { url = "https://files.pythonhosted.org/packages/48/99/0ac8678a819c28d9a370a663007581744a9f2a844e32f0fa95e1ddda5b9e/grpcio-1.74.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8efe72fde5500f47aca1ef59495cb59c885afe04ac89dd11d810f2de87d935d4", size = 10999804, upload-time = "2025-07-24T18:53:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/45/c6/a2d586300d9e14ad72e8dc211c7aecb45fe9846a51e558c5bca0c9102c7f/grpcio-1.74.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a8f0302f9ac4e9923f98d8e243939a6fb627cd048f5cd38595c97e38020dffce", size = 5987667, upload-time = "2025-07-24T18:53:07.157Z" }, - { url = "https://files.pythonhosted.org/packages/c9/57/5f338bf56a7f22584e68d669632e521f0de460bb3749d54533fc3d0fca4f/grpcio-1.74.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f609a39f62a6f6f05c7512746798282546358a37ea93c1fcbadf8b2fed162e3", size = 6655612, upload-time = "2025-07-24T18:53:09.244Z" }, - { url = "https://files.pythonhosted.org/packages/82/ea/a4820c4c44c8b35b1903a6c72a5bdccec92d0840cf5c858c498c66786ba5/grpcio-1.74.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c98e0b7434a7fa4e3e63f250456eaef52499fba5ae661c58cc5b5477d11e7182", size = 6219544, upload-time = "2025-07-24T18:53:11.221Z" }, - { url = "https://files.pythonhosted.org/packages/a4/17/0537630a921365928f5abb6d14c79ba4dcb3e662e0dbeede8af4138d9dcf/grpcio-1.74.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:662456c4513e298db6d7bd9c3b8df6f75f8752f0ba01fb653e252ed4a59b5a5d", size = 6334863, upload-time = "2025-07-24T18:53:12.925Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a6/85ca6cb9af3f13e1320d0a806658dca432ff88149d5972df1f7b51e87127/grpcio-1.74.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3d14e3c4d65e19d8430a4e28ceb71ace4728776fd6c3ce34016947474479683f", size = 7019320, upload-time = "2025-07-24T18:53:15.002Z" }, - { url = "https://files.pythonhosted.org/packages/4f/a7/fe2beab970a1e25d2eff108b3cf4f7d9a53c185106377a3d1989216eba45/grpcio-1.74.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bf949792cee20d2078323a9b02bacbbae002b9e3b9e2433f2741c15bdeba1c4", size = 6514228, upload-time = "2025-07-24T18:53:16.999Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c2/2f9c945c8a248cebc3ccda1b7a1bf1775b9d7d59e444dbb18c0014e23da6/grpcio-1.74.0-cp311-cp311-win32.whl", hash = "sha256:55b453812fa7c7ce2f5c88be3018fb4a490519b6ce80788d5913f3f9d7da8c7b", size = 3817216, upload-time = "2025-07-24T18:53:20.564Z" }, - { url = "https://files.pythonhosted.org/packages/ff/d1/a9cf9c94b55becda2199299a12b9feef0c79946b0d9d34c989de6d12d05d/grpcio-1.74.0-cp311-cp311-win_amd64.whl", hash = "sha256:86ad489db097141a907c559988c29718719aa3e13370d40e20506f11b4de0d11", size = 4495380, upload-time = "2025-07-24T18:53:22.058Z" }, - { url = "https://files.pythonhosted.org/packages/4c/5d/e504d5d5c4469823504f65687d6c8fb97b7f7bf0b34873b7598f1df24630/grpcio-1.74.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8533e6e9c5bd630ca98062e3a1326249e6ada07d05acf191a77bc33f8948f3d8", size = 5445551, upload-time = "2025-07-24T18:53:23.641Z" }, - { url = "https://files.pythonhosted.org/packages/43/01/730e37056f96f2f6ce9f17999af1556df62ee8dab7fa48bceeaab5fd3008/grpcio-1.74.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:2918948864fec2a11721d91568effffbe0a02b23ecd57f281391d986847982f6", size = 10979810, upload-time = "2025-07-24T18:53:25.349Z" }, - { url = "https://files.pythonhosted.org/packages/79/3d/09fd100473ea5c47083889ca47ffd356576173ec134312f6aa0e13111dee/grpcio-1.74.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:60d2d48b0580e70d2e1954d0d19fa3c2e60dd7cbed826aca104fff518310d1c5", size = 5941946, upload-time = "2025-07-24T18:53:27.387Z" }, - { url = "https://files.pythonhosted.org/packages/8a/99/12d2cca0a63c874c6d3d195629dcd85cdf5d6f98a30d8db44271f8a97b93/grpcio-1.74.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3601274bc0523f6dc07666c0e01682c94472402ac2fd1226fd96e079863bfa49", size = 6621763, upload-time = "2025-07-24T18:53:29.193Z" }, - { url = "https://files.pythonhosted.org/packages/9d/2c/930b0e7a2f1029bbc193443c7bc4dc2a46fedb0203c8793dcd97081f1520/grpcio-1.74.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:176d60a5168d7948539def20b2a3adcce67d72454d9ae05969a2e73f3a0feee7", size = 6180664, upload-time = "2025-07-24T18:53:30.823Z" }, - { url = "https://files.pythonhosted.org/packages/db/d5/ff8a2442180ad0867717e670f5ec42bfd8d38b92158ad6bcd864e6d4b1ed/grpcio-1.74.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e759f9e8bc908aaae0412642afe5416c9f983a80499448fcc7fab8692ae044c3", size = 6301083, upload-time = "2025-07-24T18:53:32.454Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ba/b361d390451a37ca118e4ec7dccec690422e05bc85fba2ec72b06cefec9f/grpcio-1.74.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9e7c4389771855a92934b2846bd807fc25a3dfa820fd912fe6bd8136026b2707", size = 6994132, upload-time = "2025-07-24T18:53:34.506Z" }, - { url = "https://files.pythonhosted.org/packages/3b/0c/3a5fa47d2437a44ced74141795ac0251bbddeae74bf81df3447edd767d27/grpcio-1.74.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cce634b10aeab37010449124814b05a62fb5f18928ca878f1bf4750d1f0c815b", size = 6489616, upload-time = "2025-07-24T18:53:36.217Z" }, - { url = "https://files.pythonhosted.org/packages/ae/95/ab64703b436d99dc5217228babc76047d60e9ad14df129e307b5fec81fd0/grpcio-1.74.0-cp312-cp312-win32.whl", hash = "sha256:885912559974df35d92219e2dc98f51a16a48395f37b92865ad45186f294096c", size = 3807083, upload-time = "2025-07-24T18:53:37.911Z" }, - { url = "https://files.pythonhosted.org/packages/84/59/900aa2445891fc47a33f7d2f76e00ca5d6ae6584b20d19af9c06fa09bf9a/grpcio-1.74.0-cp312-cp312-win_amd64.whl", hash = "sha256:42f8fee287427b94be63d916c90399ed310ed10aadbf9e2e5538b3e497d269bc", size = 4490123, upload-time = "2025-07-24T18:53:39.528Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d8/1004a5f468715221450e66b051c839c2ce9a985aa3ee427422061fcbb6aa/grpcio-1.74.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:2bc2d7d8d184e2362b53905cb1708c84cb16354771c04b490485fa07ce3a1d89", size = 5449488, upload-time = "2025-07-24T18:53:41.174Z" }, - { url = "https://files.pythonhosted.org/packages/94/0e/33731a03f63740d7743dced423846c831d8e6da808fcd02821a4416df7fa/grpcio-1.74.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c14e803037e572c177ba54a3e090d6eb12efd795d49327c5ee2b3bddb836bf01", size = 10974059, upload-time = "2025-07-24T18:53:43.066Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c6/3d2c14d87771a421205bdca991467cfe473ee4c6a1231c1ede5248c62ab8/grpcio-1.74.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:f6ec94f0e50eb8fa1744a731088b966427575e40c2944a980049798b127a687e", size = 5945647, upload-time = "2025-07-24T18:53:45.269Z" }, - { url = "https://files.pythonhosted.org/packages/c5/83/5a354c8aaff58594eef7fffebae41a0f8995a6258bbc6809b800c33d4c13/grpcio-1.74.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:566b9395b90cc3d0d0c6404bc8572c7c18786ede549cdb540ae27b58afe0fb91", size = 6626101, upload-time = "2025-07-24T18:53:47.015Z" }, - { url = "https://files.pythonhosted.org/packages/3f/ca/4fdc7bf59bf6994aa45cbd4ef1055cd65e2884de6113dbd49f75498ddb08/grpcio-1.74.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1ea6176d7dfd5b941ea01c2ec34de9531ba494d541fe2057c904e601879f249", size = 6182562, upload-time = "2025-07-24T18:53:48.967Z" }, - { url = "https://files.pythonhosted.org/packages/fd/48/2869e5b2c1922583686f7ae674937986807c2f676d08be70d0a541316270/grpcio-1.74.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:64229c1e9cea079420527fa8ac45d80fc1e8d3f94deaa35643c381fa8d98f362", size = 6303425, upload-time = "2025-07-24T18:53:50.847Z" }, - { url = "https://files.pythonhosted.org/packages/a6/0e/bac93147b9a164f759497bc6913e74af1cb632c733c7af62c0336782bd38/grpcio-1.74.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:0f87bddd6e27fc776aacf7ebfec367b6d49cad0455123951e4488ea99d9b9b8f", size = 6996533, upload-time = "2025-07-24T18:53:52.747Z" }, - { url = "https://files.pythonhosted.org/packages/84/35/9f6b2503c1fd86d068b46818bbd7329db26a87cdd8c01e0d1a9abea1104c/grpcio-1.74.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3b03d8f2a07f0fea8c8f74deb59f8352b770e3900d143b3d1475effcb08eec20", size = 6491489, upload-time = "2025-07-24T18:53:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/75/33/a04e99be2a82c4cbc4039eb3a76f6c3632932b9d5d295221389d10ac9ca7/grpcio-1.74.0-cp313-cp313-win32.whl", hash = "sha256:b6a73b2ba83e663b2480a90b82fdae6a7aa6427f62bf43b29912c0cfd1aa2bfa", size = 3805811, upload-time = "2025-07-24T18:53:56.798Z" }, - { url = "https://files.pythonhosted.org/packages/34/80/de3eb55eb581815342d097214bed4c59e806b05f1b3110df03b2280d6dfd/grpcio-1.74.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd3c71aeee838299c5887230b8a1822795325ddfea635edd82954c1eaa831e24", size = 4489214, upload-time = "2025-07-24T18:53:59.771Z" }, +version = "1.71.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/c5/8ad16eb7062f3d43b1b4e48f725b5ca7bbe5f0fc7ae585fff0568401bc3a/grpcio-1.71.2.tar.gz", hash = "sha256:cc7d02b21b2ec0d2479c2d98a2b9255ee8b32970ede37e42b5b6536a0fb4c47f", size = 12531104, upload-time = "2025-06-28T04:19:49.921Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/db/885a113b12bd06a454dc5521cc7206614859ab3e63d9f7acf97ad234bf19/grpcio-1.71.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:85d686d7e0ec91b58d18b4a758210581fd7cb64be680c6a0bb03aed21989013e", size = 5210788, upload-time = "2025-06-28T04:18:40.164Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1a/2ae55c56617b94b7d480d0e115819e4a41be19d81f63670aea0a99148a3d/grpcio-1.71.2-cp311-cp311-macosx_10_14_universal2.whl", hash = "sha256:08d85d387f6b8b65cd08eb174058e1c5d553e4bee3ed758bd62122b29c3217f5", size = 10334235, upload-time = "2025-06-28T04:18:42.204Z" }, + { url = "https://files.pythonhosted.org/packages/2d/33/786c6b9038c07e6e525e101f72072ea1c47f1121e301ff9eba3ecf64ff05/grpcio-1.71.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:565371de1361f152d4423ddc2c406e821e71626acdbf82f3a2496403bd7423f8", size = 5634708, upload-time = "2025-06-28T04:18:44.453Z" }, + { url = "https://files.pythonhosted.org/packages/f9/d2/4d651be50457ddc5a63be1d98c387f4db82cc0169f7887a03f38f282eb44/grpcio-1.71.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:efaa534f0fc38afaf130a974a82af37b8d17869b7fd75569df75b0572ce1a487", size = 6272196, upload-time = "2025-06-28T04:18:46.256Z" }, + { url = "https://files.pythonhosted.org/packages/df/21/5e06e38eed83011367ab5c7816954f612e2a3136a21c291c9e434c51ee78/grpcio-1.71.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e043fa4ffda1e8d16320cde3be1c922e69f6919681eee06ef1acfcd06fdae4a9", size = 5878754, upload-time = "2025-06-28T04:18:47.963Z" }, + { url = "https://files.pythonhosted.org/packages/85/6a/5b7900d90231dfdfbccb219f7270bada7f58eb4dce2b73a08ff3e5deee18/grpcio-1.71.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c6109c2e7f71aaf446636f1dc3d7a37ebc3442ba490e8c1e3e0f0dac550b68dd", size = 5966154, upload-time = "2025-06-28T04:18:49.875Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ae/8b39780a9f45fef0075fd3b90c108194a3f182848713a0df6477066472b7/grpcio-1.71.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c9e7caab80d96936d553f3ed9c088dff9772c8b42302c1cafcd098203ea7c018", size = 6587554, upload-time = "2025-06-28T04:18:51.384Z" }, + { url = "https://files.pythonhosted.org/packages/09/a8/eca124357c465ea928bffb0af616718a6d12816559f1a705117e1cb20314/grpcio-1.71.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c2409fcbd429df4aacb20e2bdd12ff508b7140a257140afeba72614b2724e836", size = 6134496, upload-time = "2025-06-28T04:18:53.364Z" }, + { url = "https://files.pythonhosted.org/packages/5b/1e/a7f46715021ed955238ab715f5b4d5949b943ef90f3391dc4955e7b65089/grpcio-1.71.2-cp311-cp311-win32.whl", hash = "sha256:0123787c64e1e52982d1a6b32224e6f265ef69e0aa088ba6b744b1bed85f756d", size = 3551426, upload-time = "2025-06-28T04:18:54.798Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e5/bc1e1276911d16f0d303205271de09beaf42300869fa1ccb2f05ecd05b42/grpcio-1.71.2-cp311-cp311-win_amd64.whl", hash = "sha256:0b695e676750cb7c9c2e2511c0b9797ab281fc1b1cc39e9d9ae05db2602c0386", size = 4217593, upload-time = "2025-06-28T04:18:56.192Z" }, + { url = "https://files.pythonhosted.org/packages/29/a2/a01b6cfc0b36ff785571a42f3dcc7c80559998fcadd16b5c101a0cdaf0d2/grpcio-1.71.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:d1b0ef55b8abef436b89fa789375365b7101732bfb688fc3904f0c8ac6d7803e", size = 5184044, upload-time = "2025-06-28T04:18:58.119Z" }, + { url = "https://files.pythonhosted.org/packages/e9/16/acebf64a0711bddd403536e3254f9686602c697624cb7ae376faa534f004/grpcio-1.71.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:0c0ac4e77a38e5ed8026b25870cdc0f7a71aa9354a2353cc90a22a396a150b3c", size = 10309517, upload-time = "2025-06-28T04:18:59.667Z" }, + { url = "https://files.pythonhosted.org/packages/82/ef/832eb985e61469c38a6e81ddc7c7a87242db914ec71b9c581836a5c801d3/grpcio-1.71.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:deb89f8dba8f2fcaec40784d3718dbb4c44f48befbf7d4da6d1b00378e20455b", size = 5587993, upload-time = "2025-06-28T04:19:01.544Z" }, + { url = "https://files.pythonhosted.org/packages/be/18/7959414c59f78b45af3c7b83ca960208b886e5eceec1aed46e1881f9d637/grpcio-1.71.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5cc3bae2de2289e476c8f1ed5f2c5cd74741a66d92f65016dc19f533acee374", size = 6236013, upload-time = "2025-06-28T04:19:03.518Z" }, + { url = "https://files.pythonhosted.org/packages/90/2d/8745729de179505f68d9fbaae3aa952f588f342faecd50eacc4704d935f1/grpcio-1.71.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf224bf8a8d85914f171c4dd028a86325f063e1661f3bef9960f4f73dc8b71d3", size = 5839034, upload-time = "2025-06-28T04:19:04.982Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f5/6ac8e39c398e5e1e0003ba50fc3f6f020d72c2f5372b54f858315dd1297b/grpcio-1.71.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e06d9e3f9cc7b7860b4d37fb0cb5e7e00071977a73a5b87a4c7da65695c4030f", size = 5935118, upload-time = "2025-06-28T04:19:06.789Z" }, + { url = "https://files.pythonhosted.org/packages/bc/cf/8f5e637cb714fe8c306b12933a4b40e9eb13aaf96bfb886662db3b56ac1b/grpcio-1.71.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6ba968281b761c52560af106504a02ff26085ad10e17e8976c047b388df40eae", size = 6560019, upload-time = "2025-06-28T04:19:08.363Z" }, + { url = "https://files.pythonhosted.org/packages/be/6b/a6ae0c16795bc56c3d469e41dacf26d88cbe12b406094af26d3f79ff5201/grpcio-1.71.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6a169f0f369b28e81d8bde6a1d4283c24d3bde80690ef05b634caaf45577d749", size = 6109409, upload-time = "2025-06-28T04:19:10.061Z" }, + { url = "https://files.pythonhosted.org/packages/87/7e/bdb355b112f0fac5bc61b4918f947ad5d4891e39447e25d221739ab76903/grpcio-1.71.2-cp312-cp312-win32.whl", hash = "sha256:df9ffd8463a2d16b6d1fef7b03035c588fdf0f0a627031e4860cea61f49808ee", size = 3539949, upload-time = "2025-06-28T04:19:11.567Z" }, + { url = "https://files.pythonhosted.org/packages/c3/12/3f503a66fa568b10b43118a0013a1cd2680117192fc0c74342f87a7c29a8/grpcio-1.71.2-cp312-cp312-win_amd64.whl", hash = "sha256:c371287913278170e09ae280d923db0baf3da6989d088dce48e88648c9933c8e", size = 4211254, upload-time = "2025-06-28T04:19:13.077Z" }, + { url = "https://files.pythonhosted.org/packages/af/7c/e472bc20859dac57336dd2bcf878e73c0d1639b3d776dffdb485ac627c51/grpcio-1.71.2-cp313-cp313-linux_armv7l.whl", hash = "sha256:57cbc2fe3c92c8af3f88b49c59317459daef18581768aa5f4cda15b7af4f4812", size = 5184261, upload-time = "2025-06-28T04:19:15.334Z" }, + { url = "https://files.pythonhosted.org/packages/7a/61/a8de01bfff9e4d71a5c5049aa3a77ff04b50db0de6ce668790aee8af69d1/grpcio-1.71.2-cp313-cp313-macosx_10_14_universal2.whl", hash = "sha256:7ec0207c9c4e9e875862d9c135b1bce29e7dec63b3167cd66a0e322e6569d8df", size = 10311688, upload-time = "2025-06-28T04:19:17.137Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e8/bb71c087520fd8f6a276e51cc63b5aba10c4fe5480f411395b6670ac7c36/grpcio-1.71.2-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:38234521040e154d2bee680f4d20a98d405920f75d616787405f899d3fe5a785", size = 5591377, upload-time = "2025-06-28T04:19:19.143Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c3/26072950d597e5c97214d48dc100dd77805f3c4e5631ef86fa2d27a99eb2/grpcio-1.71.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a2241e16bd4fd64131cfa5c89a1b9d2a84ae18dbc1e8a5817fa355f110de6c12", size = 6242061, upload-time = "2025-06-28T04:19:20.856Z" }, + { url = "https://files.pythonhosted.org/packages/47/29/4e26fa08e75b627b4e7fe24402f343205d4ed2dc6133502e36e286c0f6bb/grpcio-1.71.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6900598663eeca1a4fe028e346476845eaff54f1797a447ff62fce35ff25ed50", size = 5841164, upload-time = "2025-06-28T04:19:22.333Z" }, + { url = "https://files.pythonhosted.org/packages/22/b9/07c1972df88aae91d70a4ac02ed6a393c1ad907f2f3c1729db1fd2b8e02e/grpcio-1.71.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c522c59852d6ac4f247e2b5b2c9a6b26e6df6ef084e35faabd00bf545f15027f", size = 5936054, upload-time = "2025-06-28T04:19:24.613Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/a4123bd0e0b964652c5693654485c4f46a16d085cf6ceade790f3e5bfb07/grpcio-1.71.2-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:4db58304bdad40ae3c736a5c6850d045be17b9403255cf483f1673a6cd17b16f", size = 6565776, upload-time = "2025-06-28T04:19:26.26Z" }, + { url = "https://files.pythonhosted.org/packages/69/b8/437c4e6e60eab50d60c340d8386d789cc37ead4ebfba69fc034b53482605/grpcio-1.71.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef09b5f8539a2118391cd8f9fc9982c8f0b4e494f9417cdb537f7b577bcdf422", size = 6112460, upload-time = "2025-06-28T04:19:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/ea/50/d95b6b0c9aff4c0f9c4d5cc34759637d623487a7aaa3710fc492b5a00efa/grpcio-1.71.2-cp313-cp313-win32.whl", hash = "sha256:bb93c29311ecca4e6d0d4148a84ec18ad7efa604e814d80d232659f031871eba", size = 3539553, upload-time = "2025-06-28T04:19:29.36Z" }, + { url = "https://files.pythonhosted.org/packages/a0/63/8de0b14892c07aad98f61bf140ff95c5f51086e058ae6da40599d60f0a04/grpcio-1.71.2-cp313-cp313-win_amd64.whl", hash = "sha256:54a9bdd5f94ce1512e3cc37f2f84a776cfbaa07222764129ebc2a54f803ebd70", size = 4211232, upload-time = "2025-06-28T04:19:30.95Z" }, ] [[package]]