1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""A setup module for the GRPC Python package.""" 15 16# NOTE(https://github.com/grpc/grpc/issues/24028): allow setuptools to monkey 17# patch distutils 18import setuptools # isort:skip 19 20# Monkey Patch the unix compiler to accept ASM 21# files used by boring SSL. 22from distutils.unixccompiler import UnixCCompiler 23 24UnixCCompiler.src_extensions.append(".S") 25del UnixCCompiler 26 27import os 28import os.path 29import pathlib 30import platform 31import re 32import shlex 33import shutil 34import subprocess 35from subprocess import PIPE 36import sys 37import sysconfig 38 39import _metadata 40from setuptools import Extension 41from setuptools.command import egg_info 42 43# Redirect the manifest template from MANIFEST.in to PYTHON-MANIFEST.in. 44egg_info.manifest_maker.template = "PYTHON-MANIFEST.in" 45 46PY3 = sys.version_info.major == 3 47PYTHON_STEM = os.path.join("src", "python", "grpcio") 48CORE_INCLUDE = ( 49 "include", 50 ".", 51) 52ABSL_INCLUDE = (os.path.join("third_party", "abseil-cpp"),) 53ADDRESS_SORTING_INCLUDE = ( 54 os.path.join("third_party", "address_sorting", "include"), 55) 56CARES_INCLUDE = ( 57 os.path.join("third_party", "cares", "cares", "include"), 58 os.path.join("third_party", "cares"), 59 os.path.join("third_party", "cares", "cares"), 60) 61if "darwin" in sys.platform: 62 CARES_INCLUDE += (os.path.join("third_party", "cares", "config_darwin"),) 63if "freebsd" in sys.platform: 64 CARES_INCLUDE += (os.path.join("third_party", "cares", "config_freebsd"),) 65if "linux" in sys.platform: 66 CARES_INCLUDE += (os.path.join("third_party", "cares", "config_linux"),) 67if "openbsd" in sys.platform: 68 CARES_INCLUDE += (os.path.join("third_party", "cares", "config_openbsd"),) 69RE2_INCLUDE = (os.path.join("third_party", "re2"),) 70SSL_INCLUDE = ( 71 os.path.join("third_party", "boringssl-with-bazel", "src", "include"), 72) 73UPB_INCLUDE = (os.path.join("third_party", "upb"),) 74UPB_GRPC_GENERATED_INCLUDE = (os.path.join("src", "core", "ext", "upb-gen"),) 75UPBDEFS_GRPC_GENERATED_INCLUDE = ( 76 os.path.join("src", "core", "ext", "upbdefs-gen"), 77) 78UTF8_RANGE_INCLUDE = (os.path.join("third_party", "utf8_range"),) 79XXHASH_INCLUDE = (os.path.join("third_party", "xxhash"),) 80ZLIB_INCLUDE = (os.path.join("third_party", "zlib"),) 81README = os.path.join(PYTHON_STEM, "README.rst") 82 83# Ensure we're in the proper directory whether or not we're being used by pip. 84os.chdir(os.path.dirname(os.path.abspath(__file__))) 85sys.path.insert(0, os.path.abspath(PYTHON_STEM)) 86 87# Break import-style to ensure we can actually find our in-repo dependencies. 88import _parallel_compile_patch 89import _spawn_patch 90import grpc_core_dependencies 91import python_version 92 93import commands 94import grpc_version 95 96_parallel_compile_patch.monkeypatch_compile_maybe() 97_spawn_patch.monkeypatch_spawn() 98 99 100LICENSE = "Apache License 2.0" 101 102CLASSIFIERS = ( 103 [ 104 "Development Status :: 5 - Production/Stable", 105 "Programming Language :: Python", 106 "Programming Language :: Python :: 3", 107 ] 108 + [ 109 f"Programming Language :: Python :: {x}" 110 for x in python_version.SUPPORTED_PYTHON_VERSIONS 111 ] 112 + ["License :: OSI Approved :: Apache Software License"] 113) 114 115 116def _env_bool_value(env_name, default): 117 """Parses a bool option from an environment variable""" 118 return os.environ.get(env_name, default).upper() not in ["FALSE", "0", ""] 119 120 121BUILD_WITH_BORING_SSL_ASM = _env_bool_value( 122 "GRPC_BUILD_WITH_BORING_SSL_ASM", "True" 123) 124 125# Export this environment variable to override the platform variant that will 126# be chosen for boringssl assembly optimizations. This option is useful when 127# crosscompiling and the host platform as obtained by sysconfig.get_platform() 128# doesn't match the platform we are targeting. 129# Example value: "linux-aarch64" 130BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM = os.environ.get( 131 "GRPC_BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM", "" 132) 133 134# Environment variable to determine whether or not the Cython extension should 135# *use* Cython or use the generated C files. Note that this requires the C files 136# to have been generated by building first *with* Cython support. Even if this 137# is set to false, if the script detects that the generated `.c` file isn't 138# present, then it will still attempt to use Cython. 139BUILD_WITH_CYTHON = _env_bool_value("GRPC_PYTHON_BUILD_WITH_CYTHON", "False") 140 141# Export this variable to use the system installation of openssl. You need to 142# have the header files installed (in /usr/include/openssl) and during 143# runtime, the shared library must be installed 144BUILD_WITH_SYSTEM_OPENSSL = _env_bool_value( 145 "GRPC_PYTHON_BUILD_SYSTEM_OPENSSL", "False" 146) 147 148# Export this variable to use the system installation of zlib. You need to 149# have the header files installed (in /usr/include/) and during 150# runtime, the shared library must be installed 151BUILD_WITH_SYSTEM_ZLIB = _env_bool_value( 152 "GRPC_PYTHON_BUILD_SYSTEM_ZLIB", "False" 153) 154 155# Export this variable to use the system installation of cares. You need to 156# have the header files installed (in /usr/include/) and during 157# runtime, the shared library must be installed 158BUILD_WITH_SYSTEM_CARES = _env_bool_value( 159 "GRPC_PYTHON_BUILD_SYSTEM_CARES", "False" 160) 161 162# Export this variable to use the system installation of re2. You need to 163# have the header files installed (in /usr/include/re2) and during 164# runtime, the shared library must be installed 165BUILD_WITH_SYSTEM_RE2 = _env_bool_value("GRPC_PYTHON_BUILD_SYSTEM_RE2", "False") 166 167# Export this variable to use the system installation of abseil. You need to 168# have the header files installed (in /usr/include/absl) and during 169# runtime, the shared library must be installed 170BUILD_WITH_SYSTEM_ABSL = os.environ.get("GRPC_PYTHON_BUILD_SYSTEM_ABSL", False) 171 172# Export this variable to force building the python extension with a statically linked libstdc++. 173# At least on linux, this is normally not needed as we can build manylinux-compatible wheels on linux just fine 174# without statically linking libstdc++ (which leads to a slight increase in the wheel size). 175# This option is useful when crosscompiling wheels for aarch64 where 176# it's difficult to ensure that the crosscompilation toolchain has a high-enough version 177# of GCC (we require >=5.1) but still uses old-enough libstdc++ symbols. 178# TODO(jtattermusch): remove this workaround once issues with crosscompiler version are resolved. 179BUILD_WITH_STATIC_LIBSTDCXX = _env_bool_value( 180 "GRPC_PYTHON_BUILD_WITH_STATIC_LIBSTDCXX", "False" 181) 182 183# For local development use only: This skips building gRPC Core and its 184# dependencies, including protobuf and boringssl. This allows "incremental" 185# compilation by first building gRPC Core using make, then building only the 186# Python/Cython layers here. 187# 188# Note that this requires libboringssl.a in the libs/{dbg,opt}/ directory, which 189# may require configuring make to not use the system openssl implementation: 190# 191# make HAS_SYSTEM_OPENSSL_ALPN=0 192# 193# TODO(ericgribkoff) Respect the BUILD_WITH_SYSTEM_* flags alongside this option 194USE_PREBUILT_GRPC_CORE = _env_bool_value( 195 "GRPC_PYTHON_USE_PREBUILT_GRPC_CORE", "False" 196) 197 198# Environment variable to determine whether or not to enable coverage analysis 199# in Cython modules. 200ENABLE_CYTHON_TRACING = _env_bool_value( 201 "GRPC_PYTHON_ENABLE_CYTHON_TRACING", "False" 202) 203 204# Environment variable specifying whether or not there's interest in setting up 205# documentation building. 206ENABLE_DOCUMENTATION_BUILD = _env_bool_value( 207 "GRPC_PYTHON_ENABLE_DOCUMENTATION_BUILD", "False" 208) 209 210 211def check_linker_need_libatomic(): 212 """Test if linker on system needs libatomic.""" 213 code_test = ( 214 b"#include <atomic>\n" 215 + b"int main() { return std::atomic<int64_t>{}; }" 216 ) 217 cxx = shlex.split(os.environ.get("CXX", "c++")) 218 cpp_test = subprocess.Popen( 219 cxx + ["-x", "c++", "-std=c++17", "-"], 220 stdin=PIPE, 221 stdout=PIPE, 222 stderr=PIPE, 223 ) 224 cpp_test.communicate(input=code_test) 225 if cpp_test.returncode == 0: 226 return False 227 # Double-check to see if -latomic actually can solve the problem. 228 # https://github.com/grpc/grpc/issues/22491 229 cpp_test = subprocess.Popen( 230 cxx + ["-x", "c++", "-std=c++17", "-", "-latomic"], 231 stdin=PIPE, 232 stdout=PIPE, 233 stderr=PIPE, 234 ) 235 cpp_test.communicate(input=code_test) 236 return cpp_test.returncode == 0 237 238 239# When building extensions for macOS on a system running macOS 10.14 or newer, 240# make sure they target macOS 10.14 or newer to use C++17 stdlib properly. 241# This overrides the default behavior of distutils, which targets the macOS 242# version Python was built on. You can further customize the target macOS 243# version by setting the MACOSX_DEPLOYMENT_TARGET environment variable before 244# running setup.py. 245if sys.platform == "darwin": 246 if "MACOSX_DEPLOYMENT_TARGET" not in os.environ: 247 target_ver = sysconfig.get_config_var("MACOSX_DEPLOYMENT_TARGET") 248 if target_ver == "" or tuple(int(p) for p in target_ver.split(".")) < ( 249 10, 250 14, 251 ): 252 os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.14" 253 254# There are some situations (like on Windows) where CC, CFLAGS, and LDFLAGS are 255# entirely ignored/dropped/forgotten by distutils and its Cygwin/MinGW support. 256# We use these environment variables to thus get around that without locking 257# ourselves in w.r.t. the multitude of operating systems this ought to build on. 258# We can also use these variables as a way to inject environment-specific 259# compiler/linker flags. We assume GCC-like compilers and/or MinGW as a 260# reasonable default. 261EXTRA_ENV_COMPILE_ARGS = os.environ.get("GRPC_PYTHON_CFLAGS", None) 262EXTRA_ENV_LINK_ARGS = os.environ.get("GRPC_PYTHON_LDFLAGS", None) 263if EXTRA_ENV_COMPILE_ARGS is None: 264 EXTRA_ENV_COMPILE_ARGS = "" 265 if "win32" in sys.platform: 266 # MSVC by defaults uses C++14 and C89 so both needs to be configured. 267 EXTRA_ENV_COMPILE_ARGS += " /std:c++17" 268 EXTRA_ENV_COMPILE_ARGS += " /std:c11" 269 # We need to statically link the C++ Runtime, only the C runtime is 270 # available dynamically 271 EXTRA_ENV_COMPILE_ARGS += " /MT" 272 elif "linux" in sys.platform: 273 # GCC by defaults uses C17 so only C++17 needs to be specified. 274 EXTRA_ENV_COMPILE_ARGS += " -std=c++17" 275 EXTRA_ENV_COMPILE_ARGS += ( 276 " -fvisibility=hidden -fno-wrapv -fno-exceptions" 277 ) 278 elif "darwin" in sys.platform: 279 # AppleClang by defaults uses C17 so only C++17 needs to be specified. 280 EXTRA_ENV_COMPILE_ARGS += " -std=c++17" 281 EXTRA_ENV_COMPILE_ARGS += ( 282 " -stdlib=libc++ -fvisibility=hidden -fno-wrapv -fno-exceptions" 283 " -DHAVE_UNISTD_H" 284 ) 285 286if EXTRA_ENV_LINK_ARGS is None: 287 EXTRA_ENV_LINK_ARGS = "" 288 if "linux" in sys.platform or "darwin" in sys.platform: 289 EXTRA_ENV_LINK_ARGS += " -lpthread" 290 if check_linker_need_libatomic(): 291 EXTRA_ENV_LINK_ARGS += " -latomic" 292 if "linux" in sys.platform: 293 EXTRA_ENV_LINK_ARGS += " -static-libgcc" 294 295# Explicitly link Core Foundation framework for MacOS to ensure no symbol is 296# missing when compiled using package managers like Conda. 297if "darwin" in sys.platform: 298 EXTRA_ENV_LINK_ARGS += " -framework CoreFoundation" 299 300EXTRA_COMPILE_ARGS = shlex.split(EXTRA_ENV_COMPILE_ARGS) 301EXTRA_LINK_ARGS = shlex.split(EXTRA_ENV_LINK_ARGS) 302 303if BUILD_WITH_STATIC_LIBSTDCXX: 304 EXTRA_LINK_ARGS.append("-static-libstdc++") 305 306CYTHON_EXTENSION_PACKAGE_NAMES = () 307 308CYTHON_EXTENSION_MODULE_NAMES = ("grpc._cython.cygrpc",) 309 310CYTHON_HELPER_C_FILES = () 311 312CORE_C_FILES = tuple(grpc_core_dependencies.CORE_SOURCE_FILES) 313if "win32" in sys.platform: 314 CORE_C_FILES = filter(lambda x: "third_party/cares" not in x, CORE_C_FILES) 315 316if BUILD_WITH_SYSTEM_OPENSSL: 317 CORE_C_FILES = filter( 318 lambda x: "third_party/boringssl" not in x, CORE_C_FILES 319 ) 320 CORE_C_FILES = filter(lambda x: "src/boringssl" not in x, CORE_C_FILES) 321 SSL_INCLUDE = (os.path.join("/usr", "include", "openssl"),) 322 323if BUILD_WITH_SYSTEM_ZLIB: 324 CORE_C_FILES = filter(lambda x: "third_party/zlib" not in x, CORE_C_FILES) 325 ZLIB_INCLUDE = (os.path.join("/usr", "include"),) 326 327if BUILD_WITH_SYSTEM_CARES: 328 CORE_C_FILES = filter(lambda x: "third_party/cares" not in x, CORE_C_FILES) 329 CARES_INCLUDE = (os.path.join("/usr", "include"),) 330 331if BUILD_WITH_SYSTEM_RE2: 332 CORE_C_FILES = filter(lambda x: "third_party/re2" not in x, CORE_C_FILES) 333 RE2_INCLUDE = (os.path.join("/usr", "include", "re2"),) 334 335if BUILD_WITH_SYSTEM_ABSL: 336 CORE_C_FILES = filter( 337 lambda x: "third_party/abseil-cpp" not in x, CORE_C_FILES 338 ) 339 ABSL_INCLUDE = (os.path.join("/usr", "include"),) 340 341EXTENSION_INCLUDE_DIRECTORIES = ( 342 (PYTHON_STEM,) 343 + CORE_INCLUDE 344 + ABSL_INCLUDE 345 + ADDRESS_SORTING_INCLUDE 346 + CARES_INCLUDE 347 + RE2_INCLUDE 348 + SSL_INCLUDE 349 + UPB_INCLUDE 350 + UPB_GRPC_GENERATED_INCLUDE 351 + UPBDEFS_GRPC_GENERATED_INCLUDE 352 + UTF8_RANGE_INCLUDE 353 + XXHASH_INCLUDE 354 + ZLIB_INCLUDE 355) 356 357EXTENSION_LIBRARIES = () 358if "linux" in sys.platform: 359 EXTENSION_LIBRARIES += ("rt",) 360if not "win32" in sys.platform: 361 EXTENSION_LIBRARIES += ("m",) 362if "win32" in sys.platform: 363 EXTENSION_LIBRARIES += ( 364 "advapi32", 365 "bcrypt", 366 "dbghelp", 367 "ws2_32", 368 ) 369if BUILD_WITH_SYSTEM_OPENSSL: 370 EXTENSION_LIBRARIES += ( 371 "ssl", 372 "crypto", 373 ) 374if BUILD_WITH_SYSTEM_ZLIB: 375 EXTENSION_LIBRARIES += ("z",) 376if BUILD_WITH_SYSTEM_CARES: 377 EXTENSION_LIBRARIES += ("cares",) 378if BUILD_WITH_SYSTEM_RE2: 379 EXTENSION_LIBRARIES += ("re2",) 380if BUILD_WITH_SYSTEM_ABSL: 381 EXTENSION_LIBRARIES += tuple( 382 lib.stem[3:] 383 for lib in sorted(pathlib.Path("/usr").glob("lib*/libabsl_*.so")) 384 ) 385 386DEFINE_MACROS = (("_WIN32_WINNT", 0x600),) 387asm_files = [] 388 389 390# Quotes on Windows build macros are evaluated differently from other platforms, 391# so we must apply quotes asymmetrically in order to yield the proper result in 392# the binary. 393def _quote_build_define(argument): 394 if "win32" in sys.platform: 395 return '"\\"{}\\""'.format(argument) 396 return '"{}"'.format(argument) 397 398 399DEFINE_MACROS += ( 400 ("GRPC_XDS_USER_AGENT_NAME_SUFFIX", _quote_build_define("Python")), 401 ( 402 "GRPC_XDS_USER_AGENT_VERSION_SUFFIX", 403 _quote_build_define(_metadata.__version__), 404 ), 405) 406 407asm_key = "" 408if BUILD_WITH_BORING_SSL_ASM and not BUILD_WITH_SYSTEM_OPENSSL: 409 boringssl_asm_platform = ( 410 BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM 411 if BUILD_OVERRIDE_BORING_SSL_ASM_PLATFORM 412 else sysconfig.get_platform() 413 ) 414 if "i686" in boringssl_asm_platform: 415 print("Enabling SSE2 on %s platform" % boringssl_asm_platform) 416 EXTRA_COMPILE_ARGS.append("-msse2") 417 else: 418 print("SSE2 not enabled on %s platform" % boringssl_asm_platform) 419 # BoringSSL's gas-compatible assembly files are all internally conditioned 420 # by the preprocessor. Provided the platform has a gas-compatible assembler 421 # (i.e. not Windows), we can include the assembly files and let BoringSSL 422 # decide which ones should and shouldn't be used for the build. 423 if not boringssl_asm_platform.startswith("win"): 424 asm_key = "crypto_asm" 425 else: 426 print( 427 "ASM Builds for BoringSSL currently not supported on:", 428 boringssl_asm_platform, 429 ) 430if asm_key: 431 asm_files = grpc_core_dependencies.ASM_SOURCE_FILES[asm_key] 432else: 433 DEFINE_MACROS += (("OPENSSL_NO_ASM", 1),) 434 435if "win32" in sys.platform: 436 # TODO(zyc): Re-enable c-ares on x64 and x86 windows after fixing the 437 # ares_library_init compilation issue 438 DEFINE_MACROS += ( 439 ("WIN32_LEAN_AND_MEAN", 1), 440 ("CARES_STATICLIB", 1), 441 ("GRPC_ARES", 0), 442 ("NTDDI_VERSION", 0x06000000), 443 ("NOMINMAX", 1), 444 ) 445 if "64bit" in platform.architecture()[0]: 446 DEFINE_MACROS += (("MS_WIN64", 1),) 447 elif sys.version_info >= (3, 5): 448 # For some reason, this is needed to get access to inet_pton/inet_ntop 449 # on msvc, but only for 32 bits 450 DEFINE_MACROS += (("NTDDI_VERSION", 0x06000000),) 451else: 452 DEFINE_MACROS += ( 453 ("HAVE_CONFIG_H", 1), 454 ("GRPC_ENABLE_FORK_SUPPORT", 1), 455 ) 456 457# Fix for multiprocessing support on Apple devices. 458# TODO(vigneshbabu): Remove this once the poll poller gets fork support. 459DEFINE_MACROS += (("GRPC_DO_NOT_INSTANTIATE_POSIX_POLLER", 1),) 460 461# Fix for Cython build issue in aarch64. 462# It's required to define this macro before include <inttypes.h>. 463# <inttypes.h> was included in core/telemetry/call_tracer.h. 464# This macro should already be defined in grpc/grpc.h through port_platform.h, 465# but we're still having issue in aarch64, so we manually define the macro here. 466# TODO(xuanwn): Figure out what's going on in the aarch64 build so we can support 467# gcc + Bazel. 468DEFINE_MACROS += (("__STDC_FORMAT_MACROS", None),) 469 470LDFLAGS = tuple(EXTRA_LINK_ARGS) 471CFLAGS = tuple(EXTRA_COMPILE_ARGS) 472if "linux" in sys.platform or "darwin" in sys.platform: 473 pymodinit_type = "PyObject*" if PY3 else "void" 474 pymodinit = 'extern "C" __attribute__((visibility ("default"))) {}'.format( 475 pymodinit_type 476 ) 477 DEFINE_MACROS += (("PyMODINIT_FUNC", pymodinit),) 478 DEFINE_MACROS += (("GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK", 1),) 479 480 481def cython_extensions_and_necessity(): 482 cython_module_files = [ 483 os.path.join(PYTHON_STEM, name.replace(".", "/") + ".pyx") 484 for name in CYTHON_EXTENSION_MODULE_NAMES 485 ] 486 config = os.environ.get("CONFIG", "opt") 487 prefix = "libs/" + config + "/" 488 if USE_PREBUILT_GRPC_CORE: 489 extra_objects = [ 490 prefix + "libares.a", 491 prefix + "libboringssl.a", 492 prefix + "libgpr.a", 493 prefix + "libgrpc.a", 494 ] 495 core_c_files = [] 496 else: 497 core_c_files = list(CORE_C_FILES) 498 extra_objects = [] 499 extensions = [ 500 Extension( 501 name=module_name, 502 sources=( 503 [module_file] 504 + list(CYTHON_HELPER_C_FILES) 505 + core_c_files 506 + asm_files 507 ), 508 include_dirs=list(EXTENSION_INCLUDE_DIRECTORIES), 509 libraries=list(EXTENSION_LIBRARIES), 510 define_macros=list(DEFINE_MACROS), 511 extra_objects=extra_objects, 512 extra_compile_args=list(CFLAGS), 513 extra_link_args=list(LDFLAGS), 514 ) 515 for (module_name, module_file) in zip( 516 list(CYTHON_EXTENSION_MODULE_NAMES), cython_module_files 517 ) 518 ] 519 need_cython = BUILD_WITH_CYTHON 520 if not BUILD_WITH_CYTHON: 521 need_cython = ( 522 need_cython 523 or not commands.check_and_update_cythonization(extensions) 524 ) 525 # TODO: the strategy for conditional compiling and exposing the aio Cython 526 # dependencies will be revisited by https://github.com/grpc/grpc/issues/19728 527 return ( 528 commands.try_cythonize( 529 extensions, 530 linetracing=ENABLE_CYTHON_TRACING, 531 mandatory=BUILD_WITH_CYTHON, 532 ), 533 need_cython, 534 ) 535 536 537CYTHON_EXTENSION_MODULES, need_cython = cython_extensions_and_necessity() 538 539PACKAGE_DIRECTORIES = { 540 "": PYTHON_STEM, 541} 542 543INSTALL_REQUIRES = () 544 545EXTRAS_REQUIRES = { 546 "protobuf": "grpcio-tools>={version}".format(version=grpc_version.VERSION), 547} 548 549SETUP_REQUIRES = ( 550 INSTALL_REQUIRES + ("Sphinx~=1.8.1",) if ENABLE_DOCUMENTATION_BUILD else () 551) 552 553try: 554 import Cython 555except ImportError: 556 if BUILD_WITH_CYTHON: 557 sys.stderr.write( 558 "You requested a Cython build via GRPC_PYTHON_BUILD_WITH_CYTHON, " 559 "but do not have Cython installed. We won't stop you from using " 560 "other commands, but the extension files will fail to build.\n" 561 ) 562 elif need_cython: 563 sys.stderr.write( 564 "We could not find Cython. Setup may take 10-20 minutes.\n" 565 ) 566 SETUP_REQUIRES += ("cython>=3.0.0",) 567 568COMMAND_CLASS = { 569 "doc": commands.SphinxDocumentation, 570 "build_project_metadata": commands.BuildProjectMetadata, 571 "build_py": commands.BuildPy, 572 "build_ext": commands.BuildExt, 573 "gather": commands.Gather, 574 "clean": commands.Clean, 575} 576 577# Ensure that package data is copied over before any commands have been run: 578credentials_dir = os.path.join(PYTHON_STEM, "grpc", "_cython", "_credentials") 579try: 580 os.mkdir(credentials_dir) 581except OSError: 582 pass 583shutil.copyfile( 584 os.path.join("etc", "roots.pem"), os.path.join(credentials_dir, "roots.pem") 585) 586 587PACKAGE_DATA = { 588 # Binaries that may or may not be present in the final installation, but are 589 # mentioned here for completeness. 590 "grpc._cython": [ 591 "_credentials/roots.pem", 592 "_windows/grpc_c.32.python", 593 "_windows/grpc_c.64.python", 594 ], 595} 596PACKAGES = setuptools.find_packages(PYTHON_STEM) 597 598setuptools.setup( 599 name="grpcio", 600 version=grpc_version.VERSION, 601 description="HTTP/2-based RPC framework", 602 author="The gRPC Authors", 603 author_email="grpc-io@googlegroups.com", 604 url="https://grpc.io", 605 project_urls={ 606 "Source Code": "https://github.com/grpc/grpc", 607 "Bug Tracker": "https://github.com/grpc/grpc/issues", 608 "Documentation": "https://grpc.github.io/grpc/python", 609 }, 610 license=LICENSE, 611 classifiers=CLASSIFIERS, 612 long_description_content_type="text/x-rst", 613 long_description=open(README).read(), 614 ext_modules=CYTHON_EXTENSION_MODULES, 615 packages=list(PACKAGES), 616 package_dir=PACKAGE_DIRECTORIES, 617 package_data=PACKAGE_DATA, 618 python_requires=f">={python_version.MIN_PYTHON_VERSION}", 619 install_requires=INSTALL_REQUIRES, 620 extras_require=EXTRAS_REQUIRES, 621 setup_requires=SETUP_REQUIRES, 622 cmdclass=COMMAND_CLASS, 623) 624