Generate long_description from README.rst

This commit is contained in:
Tom Most 2019-06-04 14:38:38 -07:00
parent 106374f6f6
commit 4e919ebd86
3 changed files with 94 additions and 15 deletions

View File

@ -33,8 +33,10 @@ here.
@var notPortedModules: Modules that are not yet ported to Python 3.
"""
import io
import os
import platform
import re
import sys
from distutils.command import build_ext
@ -63,10 +65,6 @@ STATIC_PACKAGE_METADATA = dict(
'Issues': 'https://twistedmatrix.com/trac/report',
},
license="MIT",
long_description="""\
An extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
""",
classifiers=[
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
@ -211,15 +209,56 @@ def _checkPythonVersion():
def getSetupArgs(extensions=_EXTENSIONS):
def _longDescriptionArgsFromReadme(readme):
"""
Generate a PyPI long description from the readme.
@return: The keyword arguments to be used the the setup method.
@param readme: Path to the readme reStructuredText file.
@type readme: C{str}
@return: Keyword arguments to be passed to C{setuptools.setup()}.
@rtype: C{str}
"""
with io.open(readme, encoding='utf-8') as f:
readmeRst = f.read()
# Munge links of the form `NEWS <NEWS.rst>`_ to point at the appropriate
# location on GitHub so that they function when the long description is
# displayed on PyPI.
longDesc = re.sub(
r'`([^`]+)\s+<(?!https?://)([^>]+)>`_',
r'`\1 <https://github.com/twisted/twisted/blob/trunk/\2>`_',
readmeRst,
flags=re.I,
)
return {
'long_description': longDesc,
'long_description_content_type': 'text/x-rst',
}
def getSetupArgs(extensions=_EXTENSIONS, readme='README.rst'):
"""
Generate arguments for C{setuptools.setup()}
@param extensions: C extension modules to maybe build. This argument is to
be used for testing.
@type extensions: C{list} of C{ConditionalExtension}
@param readme: Path to the readme reStructuredText file. This argument is
to be used for testing.
@type readme: C{str}
@return: The keyword arguments to be used by the setup method.
@rtype: L{dict}
"""
_checkPythonVersion()
arguments = STATIC_PACKAGE_METADATA.copy()
if readme:
arguments.update(_longDescriptionArgsFromReadme(readme))
# This is a workaround for distutils behavior; ext_modules isn't
# actually used by our custom builder. distutils deep-down checks

View File

@ -8,24 +8,24 @@ Tests for parts of our release automation system.
import os
from pkg_resources import parse_requirements
from setuptools.dist import Distribution
import twisted
from twisted.trial.unittest import TestCase
from twisted.trial.unittest import SynchronousTestCase
from twisted.python import _setup, filepath
from twisted.python.compat import _PY3
from twisted.python._setup import (
BuildPy3,
getSetupArgs,
_longDescriptionArgsFromReadme,
ConditionalExtension,
_EXTRAS_REQUIRE,
)
class SetupTests(TestCase):
class SetupTests(SynchronousTestCase):
"""
Tests for L{getSetupArgs}.
"""
@ -40,7 +40,7 @@ class SetupTests(TestCase):
bad_ext = ConditionalExtension("whatever", ["whatever.c"],
condition=lambda b: False)
args = getSetupArgs(extensions=[good_ext, bad_ext])
args = getSetupArgs(extensions=[good_ext, bad_ext], readme=None)
# ext_modules should be set even though it's not used. See comment
# in getSetupArgs
@ -60,7 +60,7 @@ class SetupTests(TestCase):
ext = ConditionalExtension("whatever", ["whatever.c"],
define_macros=[("whatever", 2)])
args = getSetupArgs(extensions=[ext])
args = getSetupArgs(extensions=[ext], readme=None)
builder = args["cmdclass"]["build_ext"](Distribution())
self.patch(os, "name", "nt")
@ -69,7 +69,7 @@ class SetupTests(TestCase):
class OptionalDependenciesTests(TestCase):
class OptionalDependenciesTests(SynchronousTestCase):
"""
Tests for L{_EXTRAS_REQUIRE}
"""
@ -295,7 +295,7 @@ fakeOtherPlatform = FakeModule({"python_implementation": lambda: "lvhpy"})
class WithPlatformTests(TestCase):
class WithPlatformTests(SynchronousTestCase):
"""
Tests for L{_checkCPython} when used with a (fake) C{platform} module.
"""
@ -316,7 +316,7 @@ class WithPlatformTests(TestCase):
class BuildPy3Tests(TestCase):
class BuildPy3Tests(SynchronousTestCase):
"""
Tests for L{BuildPy3}.
"""
@ -363,3 +363,39 @@ class BuildPy3Tests(TestCase):
]),
sorted(result),
)
class LongDescriptionTests(SynchronousTestCase):
"""
Tests for C{_getLongDescriptionArgs()}
Note that the validity of the reStructuredText syntax is tested separately
using L{twine check} in L{tox.ini}.
"""
def test_generate(self):
"""
L{_longDescriptionArgsFromReadme()} outputs a L{long_description} in
reStructuredText format. Local links are transformed into absolute ones
that point at the Twisted GitHub repository.
"""
path = self.mktemp()
with open(path, 'w') as f:
f.write('\n'.join([
'Twisted',
'=======',
'',
'Changes: `NEWS <NEWS.rst>`_.',
"Read `the docs <https://twistedmatrix.com/documents/>`_.\n",
]))
self.assertEqual({
'long_description': '''\
Twisted
=======
Changes: `NEWS <https://github.com/twisted/twisted/blob/trunk/NEWS.rst>`_.
Read `the docs <https://twistedmatrix.com/documents/>`_.
''',
'long_description_content_type': 'text/x-rst',
}, _longDescriptionArgsFromReadme(path))

View File

@ -28,7 +28,7 @@
minversion=2.4
skip_missing_interpreters=True
toxworkdir=build/
envlist=lint,pyflakes,apidocs,narrativedocs,newsfragment,manifest-checker,py27-alldeps-nocov,py36-alldeps-nocov
envlist=lint,pyflakes,apidocs,narrativedocs,newsfragment,manifest-checker,twine,py27-alldeps-nocov,py36-alldeps-nocov
[testenv]
;; dependencies managed by extras in t.p._setup.py._EXTRAS_REQUIRE
@ -60,6 +60,8 @@ deps =
; Code quality checkers
manifest-checker: check-manifest
twine: twine
lint: pyflakes
lint: twistedchecker>=0.7.1
lint: diff-cover==0.9.12
@ -131,6 +133,8 @@ commands =
manifest-checker: check-manifest --ignore "docs/_build*,docs/historic/*,admin*,bin/admin*,twisted/topfiles/*.Old"
twine: twine check {distdir}/*.*
wheels: cibuildwheel --output-dir {toxinidir}/wheelhouse {toxinidir}
wheels: python setup.py sdist --formats=gztar,zip --dist-dir={toxinidir}/wheelhouse
wheels: ls -l {toxinidir}/wheelhouse