_setup.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. # -*- test-case-name: twisted.python.test.test_setup -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. # pylint: disable=I0011,C0103,C9302,W9401,W9402
  5. """
  6. Setuptools convenience functionality.
  7. This file must not import anything from Twisted, as it is loaded by C{exec} in
  8. C{setup.py}. If you need compatibility functions for this code, duplicate them
  9. here.
  10. @var _EXTRA_OPTIONS: These are the actual package names and versions that will
  11. be used by C{extras_require}. This is not passed to setup directly so that
  12. combinations of the packages can be created without the need to copy
  13. package names multiple times.
  14. @var _EXTRAS_REQUIRE: C{extras_require} is a dictionary of items that can be
  15. passed to setup.py to install optional dependencies. For example, to
  16. install the optional dev dependencies one would type::
  17. pip install -e ".[dev]"
  18. This has been supported by setuptools since 0.5a4.
  19. @var _PLATFORM_INDEPENDENT: A list of all optional cross-platform dependencies,
  20. as setuptools version specifiers, used to populate L{_EXTRAS_REQUIRE}.
  21. @var _EXTENSIONS: The list of L{ConditionalExtension} used by the setup
  22. process.
  23. @var notPortedModules: Modules that are not yet ported to Python 3.
  24. """
  25. import os
  26. import platform
  27. import sys
  28. from distutils.command import build_ext
  29. from distutils.errors import CompileError
  30. from setuptools import Extension, find_packages
  31. from setuptools.command.build_py import build_py
  32. # Do not replace this with t.p.compat imports, this file must not import
  33. # from Twisted. See the docstring.
  34. if sys.version_info < (3, 0):
  35. _PY3 = False
  36. else:
  37. _PY3 = True
  38. STATIC_PACKAGE_METADATA = dict(
  39. name="Twisted",
  40. description="An asynchronous networking framework written in Python",
  41. author="Twisted Matrix Laboratories",
  42. author_email="twisted-python@twistedmatrix.com",
  43. maintainer="Glyph Lefkowitz",
  44. maintainer_email="glyph@twistedmatrix.com",
  45. url="http://twistedmatrix.com/",
  46. license="MIT",
  47. long_description="""\
  48. An extensible framework for Python programming, with special focus
  49. on event-based network programming and multiprotocol integration.
  50. """,
  51. classifiers=[
  52. "Programming Language :: Python :: 2.7",
  53. "Programming Language :: Python :: 3",
  54. "Programming Language :: Python :: 3.3",
  55. "Programming Language :: Python :: 3.4",
  56. "Programming Language :: Python :: 3.5",
  57. ],
  58. )
  59. _dev = [
  60. 'pyflakes >= 1.0.0',
  61. 'twisted-dev-tools >= 0.0.2',
  62. 'python-subunit',
  63. 'sphinx >= 1.3.1',
  64. 'towncrier >= 17.4.0'
  65. ]
  66. if not _PY3:
  67. # These modules do not yet work on Python 3.
  68. _dev += [
  69. 'twistedchecker >= 0.4.0',
  70. 'pydoctor >= 16.2.0',
  71. ]
  72. _EXTRA_OPTIONS = dict(
  73. dev=_dev,
  74. tls=[
  75. 'pyopenssl >= 16.0.0',
  76. 'service_identity',
  77. # idna 2.3 introduced some changes that break a few things. Avoid it.
  78. # The problems were fixed in 2.4.
  79. 'idna >= 0.6, != 2.3',
  80. ],
  81. conch=[
  82. 'pyasn1',
  83. 'cryptography >= 0.9.1',
  84. 'appdirs >= 1.4.0',
  85. ],
  86. soap=['soappy'],
  87. serial=['pyserial'],
  88. osx=['pyobjc-core',
  89. 'pyobjc-framework-CFNetwork',
  90. 'pyobjc-framework-Cocoa'],
  91. windows=['pypiwin32'],
  92. http2=['h2 >= 3.0, < 4.0',
  93. 'priority >= 1.1.0, < 2.0'],
  94. )
  95. _PLATFORM_INDEPENDENT = (
  96. _EXTRA_OPTIONS['tls'] +
  97. _EXTRA_OPTIONS['conch'] +
  98. _EXTRA_OPTIONS['soap'] +
  99. _EXTRA_OPTIONS['serial'] +
  100. _EXTRA_OPTIONS['http2']
  101. )
  102. _EXTRAS_REQUIRE = {
  103. 'dev': _EXTRA_OPTIONS['dev'],
  104. 'tls': _EXTRA_OPTIONS['tls'],
  105. 'conch': _EXTRA_OPTIONS['conch'],
  106. 'soap': _EXTRA_OPTIONS['soap'],
  107. 'serial': _EXTRA_OPTIONS['serial'],
  108. 'http2': _EXTRA_OPTIONS['http2'],
  109. 'all_non_platform': _PLATFORM_INDEPENDENT,
  110. 'osx_platform': (
  111. _EXTRA_OPTIONS['osx'] + _PLATFORM_INDEPENDENT
  112. ),
  113. 'windows_platform': (
  114. _EXTRA_OPTIONS['windows'] + _PLATFORM_INDEPENDENT
  115. ),
  116. }
  117. # Scripts provided by Twisted on Python 2 and 3.
  118. _CONSOLE_SCRIPTS = [
  119. "ckeygen = twisted.conch.scripts.ckeygen:run",
  120. "cftp = twisted.conch.scripts.cftp:run",
  121. "conch = twisted.conch.scripts.conch:run",
  122. "pyhtmlizer = twisted.scripts.htmlizer:run",
  123. "tkconch = twisted.conch.scripts.tkconch:run",
  124. "trial = twisted.scripts.trial:run",
  125. "twist = twisted.application.twist._twist:Twist.main",
  126. "twistd = twisted.scripts.twistd:run",
  127. ]
  128. # Scripts provided by Twisted on Python 2 only.
  129. _CONSOLE_SCRIPTS_PY2 = [
  130. "mailmail = twisted.mail.scripts.mailmail:run",
  131. ]
  132. if not _PY3:
  133. _CONSOLE_SCRIPTS = _CONSOLE_SCRIPTS + _CONSOLE_SCRIPTS_PY2
  134. class ConditionalExtension(Extension, object):
  135. """
  136. An extension module that will only be compiled if certain conditions are
  137. met.
  138. @param condition: A callable of one argument which returns True or False to
  139. indicate whether the extension should be built. The argument is an
  140. instance of L{build_ext_twisted}, which has useful methods for checking
  141. things about the platform.
  142. """
  143. def __init__(self, *args, **kwargs):
  144. self.condition = kwargs.pop("condition", lambda builder: True)
  145. Extension.__init__(self, *args, **kwargs)
  146. # The C extensions used for Twisted.
  147. _EXTENSIONS = [
  148. ConditionalExtension(
  149. "twisted.test.raiser",
  150. sources=["src/twisted/test/raiser.c"],
  151. condition=lambda _: _isCPython),
  152. ConditionalExtension(
  153. "twisted.internet.iocpreactor.iocpsupport",
  154. sources=[
  155. "src/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c",
  156. "src/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c",
  157. ],
  158. libraries=["ws2_32"],
  159. condition=lambda _: _isCPython and sys.platform == "win32"),
  160. ConditionalExtension(
  161. "twisted.python._sendmsg",
  162. sources=["src/twisted/python/_sendmsg.c"],
  163. condition=lambda _: not _PY3 and sys.platform != "win32"),
  164. ]
  165. def getSetupArgs(extensions=_EXTENSIONS):
  166. """
  167. @return: The keyword arguments to be used the the setup method.
  168. @rtype: L{dict}
  169. """
  170. arguments = STATIC_PACKAGE_METADATA.copy()
  171. # This is a workaround for distutils behavior; ext_modules isn't
  172. # actually used by our custom builder. distutils deep-down checks
  173. # to see if there are any ext_modules defined before invoking
  174. # the build_ext command. We need to trigger build_ext regardless
  175. # because it is the thing that does the conditional checks to see
  176. # if it should build any extensions. The reason we have to delay
  177. # the conditional checks until then is that the compiler objects
  178. # are not yet set up when this code is executed.
  179. arguments["ext_modules"] = extensions
  180. # Use custome class to build the extensions.
  181. class my_build_ext(build_ext_twisted):
  182. conditionalExtensions = extensions
  183. command_classes = {
  184. 'build_ext': my_build_ext,
  185. }
  186. if sys.version_info[0] >= 3:
  187. requirements = ["zope.interface >= 4.0.2"]
  188. command_classes['build_py'] = BuildPy3
  189. else:
  190. requirements = ["zope.interface >= 3.6.0"]
  191. requirements.append("constantly >= 15.1")
  192. requirements.append("incremental >= 16.10.1")
  193. requirements.append("Automat >= 0.3.0")
  194. requirements.append("hyperlink >= 17.1.1")
  195. arguments.update(dict(
  196. packages=find_packages("src"),
  197. use_incremental=True,
  198. setup_requires=["incremental >= 16.10.1"],
  199. install_requires=requirements,
  200. entry_points={
  201. 'console_scripts': _CONSOLE_SCRIPTS
  202. },
  203. cmdclass=command_classes,
  204. include_package_data=True,
  205. zip_safe=False,
  206. extras_require=_EXTRAS_REQUIRE,
  207. package_dir={"": "src"},
  208. ))
  209. return arguments
  210. class BuildPy3(build_py, object):
  211. """
  212. A version of build_py that doesn't install the modules that aren't yet
  213. ported to Python 3.
  214. """
  215. def find_package_modules(self, package, package_dir):
  216. modules = [
  217. module for module
  218. in build_py.find_package_modules(self, package, package_dir)
  219. if ".".join([module[0], module[1]]) not in notPortedModules]
  220. return modules
  221. ## Helpers and distutil tweaks
  222. class build_ext_twisted(build_ext.build_ext, object):
  223. """
  224. Allow subclasses to easily detect and customize Extensions to
  225. build at install-time.
  226. """
  227. def prepare_extensions(self):
  228. """
  229. Prepare the C{self.extensions} attribute (used by
  230. L{build_ext.build_ext}) by checking which extensions in
  231. I{conditionalExtensions} should be built. In addition, if we are
  232. building on NT, define the WIN32 macro to 1.
  233. """
  234. # always define WIN32 under Windows
  235. if os.name == 'nt':
  236. self.define_macros = [("WIN32", 1)]
  237. else:
  238. self.define_macros = []
  239. # On Solaris 10, we need to define the _XOPEN_SOURCE and
  240. # _XOPEN_SOURCE_EXTENDED macros to build in order to gain access to
  241. # the msg_control, msg_controllen, and msg_flags members in
  242. # sendmsg.c. (according to
  243. # http://stackoverflow.com/questions/1034587). See the documentation
  244. # of X/Open CAE in the standards(5) man page of Solaris.
  245. if sys.platform.startswith('sunos'):
  246. self.define_macros.append(('_XOPEN_SOURCE', 1))
  247. self.define_macros.append(('_XOPEN_SOURCE_EXTENDED', 1))
  248. self.extensions = [
  249. x for x in self.conditionalExtensions if x.condition(self)
  250. ]
  251. for ext in self.extensions:
  252. ext.define_macros.extend(self.define_macros)
  253. def build_extensions(self):
  254. """
  255. Check to see which extension modules to build and then build them.
  256. """
  257. self.prepare_extensions()
  258. build_ext.build_ext.build_extensions(self)
  259. def _remove_conftest(self):
  260. for filename in ("conftest.c", "conftest.o", "conftest.obj"):
  261. try:
  262. os.unlink(filename)
  263. except EnvironmentError:
  264. pass
  265. def _compile_helper(self, content):
  266. conftest = open("conftest.c", "w")
  267. try:
  268. with conftest:
  269. conftest.write(content)
  270. try:
  271. self.compiler.compile(["conftest.c"], output_dir='')
  272. except CompileError:
  273. return False
  274. return True
  275. finally:
  276. self._remove_conftest()
  277. def _check_header(self, header_name):
  278. """
  279. Check if the given header can be included by trying to compile a file
  280. that contains only an #include line.
  281. """
  282. self.compiler.announce("checking for %s ..." % header_name, 0)
  283. return self._compile_helper("#include <%s>\n" % header_name)
  284. def _checkCPython(sys=sys, platform=platform):
  285. """
  286. Checks if this implementation is CPython.
  287. This uses C{platform.python_implementation}.
  288. This takes C{sys} and C{platform} kwargs that by default use the real
  289. modules. You shouldn't care about these -- they are for testing purposes
  290. only.
  291. @return: C{False} if the implementation is definitely not CPython, C{True}
  292. otherwise.
  293. """
  294. return platform.python_implementation() == "CPython"
  295. _isCPython = _checkCPython()
  296. notPortedModules = [
  297. "twisted.internet.glib2reactor",
  298. "twisted.internet.gtk2reactor",
  299. "twisted.internet.pyuisupport",
  300. "twisted.internet.test.process_connectionlost",
  301. "twisted.internet.test.process_gireactornocompat",
  302. "twisted.internet.tksupport",
  303. "twisted.mail.__init__",
  304. "twisted.mail.alias",
  305. "twisted.mail.bounce",
  306. "twisted.mail.imap4",
  307. "twisted.mail.mail",
  308. "twisted.mail.maildir",
  309. "twisted.mail.pb",
  310. "twisted.mail.pop3",
  311. "twisted.mail.pop3client",
  312. "twisted.mail.protocols",
  313. "twisted.mail.relay",
  314. "twisted.mail.relaymanager",
  315. "twisted.mail.scripts.__init__",
  316. "twisted.mail.scripts.mailmail",
  317. "twisted.mail.tap",
  318. "twisted.mail.test.pop3testserver",
  319. "twisted.mail.test.test_bounce",
  320. "twisted.mail.test.test_imap",
  321. "twisted.mail.test.test_mail",
  322. "twisted.mail.test.test_mailmail",
  323. "twisted.mail.test.test_options",
  324. "twisted.mail.test.test_pop3",
  325. "twisted.mail.test.test_pop3client",
  326. "twisted.mail.test.test_scripts",
  327. "twisted.news.__init__",
  328. "twisted.news.database",
  329. "twisted.news.news",
  330. "twisted.news.nntp",
  331. "twisted.news.tap",
  332. "twisted.news.test.__init__",
  333. "twisted.news.test.test_database",
  334. "twisted.news.test.test_news",
  335. "twisted.news.test.test_nntp",
  336. "twisted.plugins.twisted_inet",
  337. "twisted.plugins.twisted_mail",
  338. "twisted.plugins.twisted_names",
  339. "twisted.plugins.twisted_news",
  340. "twisted.plugins.twisted_portforward",
  341. "twisted.plugins.twisted_runner",
  342. "twisted.plugins.twisted_socks",
  343. "twisted.plugins.twisted_words",
  344. "twisted.protocols.ident",
  345. "twisted.protocols.mice.__init__",
  346. "twisted.protocols.mice.mouseman",
  347. "twisted.protocols.shoutcast",
  348. "twisted.python._pydoctor",
  349. "twisted.python._release",
  350. "twisted.python.finalize",
  351. "twisted.python.formmethod",
  352. "twisted.python.hook",
  353. "twisted.python.rebuild",
  354. "twisted.python.release",
  355. "twisted.python.shortcut",
  356. "twisted.python.test.cmodulepullpipe",
  357. "twisted.python.test.test_fakepwd",
  358. "twisted.python.test.test_pydoctor",
  359. "twisted.python.test.test_release",
  360. "twisted.python.test.test_win32",
  361. "twisted.tap.portforward",
  362. "twisted.tap.socks",
  363. "twisted.test.crash_test_dummy",
  364. "twisted.test.myrebuilder1",
  365. "twisted.test.myrebuilder2",
  366. "twisted.test.test_formmethod",
  367. "twisted.test.test_hook",
  368. "twisted.test.test_ident",
  369. "twisted.test.test_rebuild",
  370. "twisted.test.test_shortcut",
  371. "twisted.test.test_strerror",
  372. "twisted.web.domhelpers",
  373. "twisted.web.microdom",
  374. "twisted.web.rewrite",
  375. "twisted.web.soap",
  376. "twisted.web.sux",
  377. "twisted.web.test.test_domhelpers",
  378. "twisted.web.test.test_html",
  379. "twisted.web.test.test_soap",
  380. "twisted.web.test.test_xml",
  381. "twisted.words.tap",
  382. "twisted.words.test.test_tap",
  383. ]