diff --git docs/index.rst docs/index.rst index 1172a49..a4eaf5f 100644 --- docs/index.rst +++ docs/index.rst @@ -7,6 +7,7 @@ Contents: :maxdepth: 2 :includehidden: + installation/index core/index conch/index lore/index diff --git docs/installation/howto/optional.rst docs/installation/howto/optional.rst new file mode 100644 index 0000000..5805286 --- /dev/null +++ docs/installation/howto/optional.rst @@ -0,0 +1,151 @@ + +:LastChangedDate: $LastChangedDate$ +:LastChangedRevision: $LastChangedRevision$ +:LastChangedBy: $LastChangedBy$ + + + + + +Installing Optional Dependencies +================================ + + + + +This document describes how to install optional dependencies that Twisted's developers find helpful. +The target audience of this document is someone who is both familiar with pip and would like to install Twisted and several of its optional dependencies. + + + +Twisted takes advantage of setuptools' `extra_requires` functionality to simplify the process of installing optional dependencies. +In the list below, the `italicized` word is the `extra option` that is passed to `pip` to install an optional set of dependencies. + + + + +.. _dev : + +- `dev` - packages to aid in the development of Twisted (linters, documentation builder, etc.). + - `twistedchecker`_ + - `pyflakes`_ + - `twisted-dev-tools`_ + - `python-subunit`_ + - `sphinx`_ + - `pydoctor`_ + + + + +.. _tls : + +- `tls` - packages that are needed to work with `TLS` from twisted. + - `pyopenssl`_ + - `service_identity`_ + + + + + +.. _conch : + +- `conch` - packages for working with conch/ssh. + - `gmpy`_ + - `pyasn1`_ + - `pycrypto`_ + + + + + +.. _soap : + +- `soap` - installs the `soappy`_ package to work with SOAP. + + + + + +.. _serial : + +- `serial` - installs the `pyserial`_ package to work with serial data. + + + + + +.. _all_non_plat : + +- `all_non_plat` - install all of the optional dependencies included in the the following options: :ref:`dev`, :ref:`tls`, :ref:`conch`, :ref:`soap`, and :ref:`serial` options. + + + + + +The following install all of the optional dependencies listed above with the addition of a platform specific library. + + + + + +.. _osx_plat : + +- `osx_plat` installs `pyobjc`_ to work with Objective-C apis. + + + + + +.. _windows_plat : + +- `windows_plat` installs `pypiwin32`_ to work with Windows' apis. + + + + + +Installing Twisted with all of the :ref:`dev` options would be done using the following: + + + + + +.. code-block:: shell + + $ pip install "twisted[dev]" + + + + + +To install multiple options at the same time, you need only provide `pip` a comma seperated list of options that you would like to install. +For example, to install the :ref:`dev` and :ref:`tls` extra packages at the same time, you'd call `pip` like so: + + + + + +.. code-block:: shell + + $ pip install "twisted[dev, tls]" + + + + + +.. _pip: https://pip.pypa.io/en/latest/quickstart.html +.. _twistedchecker: https://pypi.python.org/pypi/TwistedChecker +.. _pyflakes: https://pypi.python.org/pypi/pyflakes +.. _twisted-dev-tools: https://pypi.python.org/pypi/twisted-dev-tools +.. _python-subunit: https://pypi.python.org/pypi/python-subunit +.. _sphinx: https://pypi.python.org/pypi/Sphinx/1.3b1 +.. _pydoctor: https://pypi.python.org/pypi/pydoctor +.. _pyopenssl: https://pypi.python.org/pypi/pyOpenSSL +.. _service_identity: https://pypi.python.org/pypi/service_identity +.. _gmpy: https://pypi.python.org/pypi/gmpy/1.17 +.. _pyasn1: https://pypi.python.org/pypi/pyasn1 +.. _pycrypto: https://pypi.python.org/pypi/pycrypto +.. _soappy: https://pypi.python.org/pypi/SOAPpy +.. _pyserial: https://pypi.python.org/pypi/pyserial +.. _pyobjc: https://pypi.python.org/pypi/pyobjc +.. _pypiwin32: https://pypi.python.org/pypi/pypiwin32 diff --git docs/installation/index.rst docs/installation/index.rst new file mode 100644 index 0000000..7f44260 --- /dev/null +++ docs/installation/index.rst @@ -0,0 +1,22 @@ + +:LastChangedDate: $LastChangedDate$ +:LastChangedRevision: $LastChangedRevision$ +:LastChangedBy: $LastChangedBy$ + +Installing Twisted +================== + + +.. toctree:: + :hidden: + + + + + howto/optional + + + + +- :doc:`Installing Optional Dependencies `: documentation + on how to install Twisted's optional dependencies. diff --git setup.py setup.py index 26f052b..e63f1b5 100755 --- setup.py +++ setup.py @@ -54,7 +54,7 @@ dependency resolution is disabled. from twisted.python.dist import ( STATIC_PACKAGE_METADATA, getDataFiles, getExtensions, getAllScripts, - getPackages, setup) + getPackages, setup, EXTRAS_REQUIRE) scripts = getAllScripts() @@ -62,6 +62,7 @@ dependency resolution is disabled. packages=getPackages('twisted'), conditionalExtensions=getExtensions(), scripts=scripts, + extras_require=EXTRAS_REQUIRE, data_files=getDataFiles('twisted'), **STATIC_PACKAGE_METADATA)) diff --git twisted/python/dist.py twisted/python/dist.py index 63b36b3..ef7bab9 100644 --- twisted/python/dist.py +++ twisted/python/dist.py @@ -49,6 +49,54 @@ twisted_subprojects = ["conch", "lore", "mail", "names", "news", "pair", "runner", "web", "words"] +# These are the actual package names and versions that will +# be used by extras_require. This is not passed to setup +# directly so that combinations of the packages can be created +# without the need to copy package names multiple times. +_extra_options = dict( + dev=['twistedchecker >= 0.2.0', + 'pyflakes >= 0.8.1', + 'twisted-dev-tools >= 0.0.2', + 'python-subunit', + 'sphinx >= 1.2.2', + 'pydoctor >= 0.5'], + tls=['pyopenssl >= 0.11', + 'service_identity'], + conch=['gmpy', + 'pyasn1', + 'pycrypto'], + soap=['soappy'], + serial=['pyserial'], + osx=['pyobjc'], + windows=['pypiwin32'] +) + +_platform_independent = ( + _extra_options['dev'] + + _extra_options['tls'] + + _extra_options['conch'] + + _extra_options['soap'] + + _extra_options['serial'] +) + +# extras_require is a dictionary of items that can be passed to setup.py +# to install optional dependencies. For example, to install the optional +# dev dependencies one would type `pip install -e ".[dev]"` +# This has been supported by setuptools since 0.5a4 +EXTRAS_REQUIRE = { + 'dev': _extra_options['dev'], + 'tls': _extra_options['tls'], + 'conch': _extra_options['conch'], + 'soap': _extra_options['soap'], + 'serial': _extra_options['serial'], + 'all_non_plat': _platform_independent, + 'osx_plat': ( + _extra_options['osx'] + _platform_independent + ), + 'windows_plat':( + _extra_options['windows'] + _platform_independent + ), +} class ConditionalExtension(Extension): diff --git twisted/python/test/test_dist.py twisted/python/test/test_dist.py index d2288ee..a3ca4d2 100644 --- twisted/python/test/test_dist.py +++ twisted/python/test/test_dist.py @@ -9,13 +9,13 @@ Tests for parts of our release automation system. import os import sys -from distutils.core import Distribution +from setuptools.dist import Distribution from twisted.trial.unittest import TestCase from twisted.python import dist from twisted.python.dist import (get_setup_args, ConditionalExtension, - build_scripts_twisted) + build_scripts_twisted, EXTRAS_REQUIRE) from twisted.python.filepath import FilePath @@ -58,6 +58,150 @@ class SetupTest(TestCase): self.assertEqual(ext.define_macros, [("whatever", 2), ("WIN32", 1)]) +class OptionalDependenciesTests(TestCase): + """ + Tests for L{dist.EXTRA_REQUIRES} + """ + def test_distributeTakesExtrasRequire(self): + """ + Test that setuptools' Distribution object can use extra_requires. + """ + extras = dict(im_an_extra_dependency="thing") + attrs = dict(extras_require=extras) + dist = Distribution(attrs) + self.assertEqual( + extras, + dist.extras_require + ) + + def test_extrasRequireDictContainsKeys(self): + """ + L{dist.EXTRA_REQUIRES} C{dev} option contains a valid + list with correct dependecies. + """ + self.assertIn('dev', EXTRAS_REQUIRE) + self.assertIn('tls', EXTRAS_REQUIRE) + self.assertIn('conch', EXTRAS_REQUIRE) + self.assertIn('soap', EXTRAS_REQUIRE) + self.assertIn('serial', EXTRAS_REQUIRE) + self.assertIn('all_non_plat', EXTRAS_REQUIRE) + self.assertIn('osx_plat', EXTRAS_REQUIRE) + self.assertIn('windows_plat', EXTRAS_REQUIRE) + + def test_extrasRequiresDevDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{dev} option contains the correct + dependencies. + """ + deps = EXTRAS_REQUIRE['dev'] + self.assertIn('twistedchecker >= 0.2.0', deps) + self.assertIn('pyflakes >= 0.8.1', deps) + self.assertIn('twisted-dev-tools >= 0.0.2', deps) + self.assertIn('python-subunit', deps) + self.assertIn('sphinx >= 1.2.2', deps) + self.assertIn('pydoctor >= 0.5', deps) + + def test_extrasRequiresTlsDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{tls} option contains the correct + dependencies. + """ + deps = EXTRAS_REQUIRE['tls'] + self.assertIn('pyopenssl >= 0.11', deps) + self.assertIn('service_identity', deps) + + def test_extrasRequiresConchDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{conch} option contains the correct + dependencies. + """ + deps = EXTRAS_REQUIRE['conch'] + self.assertIn('gmpy', deps) + self.assertIn('pyasn1', deps) + self.assertIn('pycrypto', deps) + + def test_extrasRequiresSoapDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{soap} option contains the correct + dependecies. + """ + self.assertIn( + 'soappy', + EXTRAS_REQUIRE['soap'] + ) + + def test_extrasRequiresSerialDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{serial} option contains the correct + dependencies. + """ + self.assertIn( + 'pyserial', + EXTRAS_REQUIRE['serial'] + ) + + def test_extrasRequiresAllNonPlatDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{all_non_plat} option contains the + correct dependencies. + """ + deps = EXTRAS_REQUIRE['all_non_plat'] + self.assertIn('twistedchecker >= 0.2.0', deps) + self.assertIn('pyflakes >= 0.8.1', deps) + self.assertIn('twisted-dev-tools >= 0.0.2', deps) + self.assertIn('python-subunit', deps) + self.assertIn('sphinx >= 1.2.2', deps) + self.assertIn('pydoctor >= 0.5', deps) + self.assertIn('pyopenssl >= 0.11', deps) + self.assertIn('service_identity', deps) + self.assertIn('gmpy', deps) + self.assertIn('pyasn1', deps) + self.assertIn('pycrypto', deps) + self.assertIn('soappy', deps) + self.assertIn('pyserial', deps) + + def test_extrasRequiresOsxPlatDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{osx_plat} option contains the correct + dependecies. + """ + deps = EXTRAS_REQUIRE['osx_plat'] + self.assertIn('twistedchecker >= 0.2.0', deps) + self.assertIn('pyflakes >= 0.8.1', deps) + self.assertIn('twisted-dev-tools >= 0.0.2', deps) + self.assertIn('python-subunit', deps) + self.assertIn('sphinx >= 1.2.2', deps) + self.assertIn('pydoctor >= 0.5', deps) + self.assertIn('pyopenssl >= 0.11', deps) + self.assertIn('service_identity', deps) + self.assertIn('gmpy', deps) + self.assertIn('pyasn1', deps) + self.assertIn('pycrypto', deps) + self.assertIn('soappy', deps) + self.assertIn('pyserial', deps) + self.assertIn('pyobjc', deps) + + def test_extrasRequiresWindowsPlatDepsAreValid(self): + """ + L{dist.EXTRA_REQUIRES} C{windows_plat} option contains the correct + dependecies. + """ + deps = EXTRAS_REQUIRE['windows_plat'] + self.assertIn('twistedchecker >= 0.2.0', deps) + self.assertIn('pyflakes >= 0.8.1', deps) + self.assertIn('twisted-dev-tools >= 0.0.2', deps) + self.assertIn('python-subunit', deps) + self.assertIn('sphinx >= 1.2.2', deps) + self.assertIn('pydoctor >= 0.5', deps) + self.assertIn('pyopenssl >= 0.11', deps) + self.assertIn('service_identity', deps) + self.assertIn('gmpy', deps) + self.assertIn('pyasn1', deps) + self.assertIn('pycrypto', deps) + self.assertIn('soappy', deps) + self.assertIn('pyserial', deps) + self.assertIn('pypiwin32', deps) + class GetExtensionsTest(TestCase): """ diff --git twisted/topfiles/3696.misc twisted/topfiles/3696.misc new file mode 100644 index 0000000..24d3d09 --- /dev/null +++ twisted/topfiles/3696.misc @@ -0,0 +1 @@ +Optional dependencies can be installed using the extra_requires facility provided by setuptools. \ No newline at end of file