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