setup.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import codecs
  2. import glob
  3. import os
  4. import re
  5. import subprocess
  6. import urllib.request
  7. import tarfile
  8. import tempfile
  9. from pkg_resources import parse_requirements
  10. from setuptools import setup, find_packages
  11. from setuptools.command.develop import develop
  12. from setuptools.command.install import install
  13. class cd:
  14. """Context manager for changing the current working directory"""
  15. def __init__(self, newPath):
  16. self.newPath = os.path.expanduser(newPath)
  17. def __enter__(self):
  18. self.savedPath = os.getcwd()
  19. os.chdir(self.newPath)
  20. def __exit__(self, etype, value, traceback):
  21. os.chdir(self.savedPath)
  22. def proto_compile(output_path):
  23. import grpc_tools.protoc
  24. cli_args = ['grpc_tools.protoc',
  25. '--proto_path=hivemind/proto', f'--python_out={output_path}',
  26. f'--grpc_python_out={output_path}'] + glob.glob('hivemind/proto/*.proto')
  27. code = grpc_tools.protoc.main(cli_args)
  28. if code: # hint: if you get this error in jupyter, run in console for richer error message
  29. raise ValueError(f"{' '.join(cli_args)} finished with exit code {code}")
  30. # Make pb2 imports in generated scripts relative
  31. for script in glob.iglob(f'{output_path}/*.py'):
  32. with open(script, 'r+') as file:
  33. code = file.read()
  34. file.seek(0)
  35. file.write(re.sub(r'\n(import .+_pb2.*)', 'from . \\1', code))
  36. file.truncate()
  37. def install_libp2p_daemon():
  38. # check go version:
  39. try:
  40. proc = subprocess.Popen(['go', 'version'],
  41. stdout=subprocess.PIPE)
  42. result, _ = proc.communicate()
  43. result = result.decode('ascii', 'replace')
  44. _, _, version, _ = result.split(' ')
  45. version = version.lstrip('go')
  46. if version < "1.13":
  47. raise EnvironmentError(f'newer version of go required: must be >= 1.13, found {version}')
  48. except FileNotFoundError:
  49. raise FileNotFoundError('could not find golang installation')
  50. with tempfile.TemporaryDirectory() as tempdir:
  51. url = 'https://github.com/libp2p/go-libp2p-daemon/archive/master.tar.gz'
  52. dest = os.path.join(tempdir, 'libp2p-daemin.tar.gz')
  53. urllib.request.urlretrieve(url, os.path.join(tempdir, dest))
  54. tar = tarfile.open(dest, 'r:gz')
  55. tar.extractall(tempdir)
  56. tar.close()
  57. with cd(os.path.join(tempdir, 'go-libp2p-daemon-master')):
  58. status = os.system('go install ./...')
  59. if status:
  60. raise RuntimeError('Failed to build or install libp2p-daemon:'\
  61. f' exited with status code :{status}')
  62. class ProtoCompileInstall(install):
  63. def run(self):
  64. proto_compile(os.path.join(self.build_lib, 'hivemind', 'proto'))
  65. super().run()
  66. class ProtoCompileDevelop(develop):
  67. def run(self):
  68. proto_compile(os.path.join('hivemind', 'proto'))
  69. super().run()
  70. class LibP2PInstall(install):
  71. def run(self):
  72. install_libp2p_daemon()
  73. here = os.path.abspath(os.path.dirname(__file__))
  74. with open('requirements.txt') as requirements_file:
  75. install_requires = list(map(str, parse_requirements(requirements_file)))
  76. # loading version from setup.py
  77. with codecs.open(os.path.join(here, 'hivemind/__init__.py'), encoding='utf-8') as init_file:
  78. version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", init_file.read(), re.M)
  79. version_string = version_match.group(1)
  80. extras = {}
  81. with open('requirements-dev.txt') as dev_requirements_file:
  82. extras['dev'] = list(map(str, parse_requirements(dev_requirements_file)))
  83. with open('requirements-docs.txt') as docs_requirements_file:
  84. extras['docs'] = list(map(str, parse_requirements(docs_requirements_file)))
  85. extras['all'] = extras['dev'] + extras['docs']
  86. setup(
  87. name='hivemind',
  88. version=version_string,
  89. cmdclass={'install': ProtoCompileInstall, 'develop': ProtoCompileDevelop, 'libp2p': LibP2PInstall},
  90. description='Decentralized deep learning in PyTorch',
  91. long_description='Decentralized deep learning in PyTorch. Built to train giant models on '
  92. 'thousands of volunteers across the world.',
  93. author='Learning@home & contributors',
  94. author_email='mryabinin0@gmail.com',
  95. url="https://github.com/learning-at-home/hivemind",
  96. packages=find_packages(exclude=['tests']),
  97. package_data={'hivemind': ['proto/*']},
  98. include_package_data=True,
  99. license='MIT',
  100. setup_requires=['grpcio-tools'],
  101. install_requires=install_requires,
  102. extras_require=extras,
  103. classifiers=[
  104. 'Development Status :: 4 - Beta',
  105. 'Intended Audience :: Developers',
  106. 'Intended Audience :: Science/Research',
  107. 'License :: OSI Approved :: MIT License',
  108. 'Programming Language :: Python :: 3',
  109. 'Programming Language :: Python :: 3.7',
  110. 'Programming Language :: Python :: 3.8',
  111. 'Programming Language :: Python :: 3.9',
  112. 'Topic :: Scientific/Engineering',
  113. 'Topic :: Scientific/Engineering :: Mathematics',
  114. 'Topic :: Scientific/Engineering :: Artificial Intelligence',
  115. 'Topic :: Software Development',
  116. 'Topic :: Software Development :: Libraries',
  117. 'Topic :: Software Development :: Libraries :: Python Modules',
  118. ],
  119. entry_points={
  120. 'console_scripts': ['hivemind-server = hivemind.hivemind_cli.run_server:main', ]
  121. },
  122. # What does your project relate to?
  123. keywords='pytorch, deep learning, machine learning, gpu, distributed computing, volunteer computing, dht',
  124. )