Merged in nicoddemus/pytest/plugins-index (pull request #76)

Script to generate docs with a list of pytest plugins from PyPI
This commit is contained in:
holger krekel 2013-10-12 14:27:43 +02:00
commit 8550ea0728
3 changed files with 328 additions and 0 deletions

179
doc/en/plugins_index.py Normal file
View File

@ -0,0 +1,179 @@
'''
Script to generate the file `plugins_index.txt` with information about pytest plugins taken directly
from a live PyPI server.
This will evolve to include test compatibility (pythons and pytest versions) information also.
'''
from collections import namedtuple
import datetime
from distutils.version import LooseVersion
import itertools
from optparse import OptionParser
import os
import sys
import xmlrpclib
#===================================================================================================
# iter_plugins
#===================================================================================================
def iter_plugins(client, search='pytest-'):
'''
Returns an iterator of (name, version) from PyPI.
:param client: xmlrpclib.ServerProxy
:param search: package names to search for
'''
for plug_data in client.search({'name' : search}):
yield plug_data['name'], plug_data['version']
#===================================================================================================
# get_latest_versions
#===================================================================================================
def get_latest_versions(plugins):
'''
Returns an iterator of (name, version) from the given list of (name, version), but returning
only the latest version of the package. Uses distutils.LooseVersion to ensure compatibility
with PEP386.
'''
plugins = [(name, LooseVersion(version)) for (name, version) in plugins]
for name, grouped_plugins in itertools.groupby(plugins, key=lambda x: x[0]):
name, loose_version = list(grouped_plugins)[-1]
yield name, str(loose_version)
#===================================================================================================
# obtain_plugins_table
#===================================================================================================
def obtain_plugins_table(plugins, client):
'''
Returns information to populate a table of plugins, their versions, authors, etc.
The returned information is a list of columns of `ColumnData` namedtuples(text, link). Link
can be None if the text for that column should not be linked to anything.
:param plugins: list of (name, version)
:param client: xmlrpclib.ServerProxy
'''
rows = []
ColumnData = namedtuple('ColumnData', 'text link')
headers = ['Name', 'Version', 'Author', 'Summary']
for package_name, version in plugins:
release_data = client.release_data(package_name, version)
row = (
ColumnData(package_name, release_data['package_url']),
ColumnData(version, release_data['release_url']),
ColumnData(release_data['author'], release_data['author_email']),
ColumnData(release_data['summary'], None),
)
assert len(row) == len(headers)
rows.append(row)
return headers, rows
#===================================================================================================
# generate_plugins_index_from_table
#===================================================================================================
def generate_plugins_index_from_table(filename, headers, rows):
'''
Generates a RST file with the table data given.
:param filename: output filename
:param headers: see `obtain_plugins_table`
:param rows: see `obtain_plugins_table`
'''
# creates a list of rows, each being a str containing appropriate column text and link
table_texts = []
for row in rows:
column_texts = []
for i, col_data in enumerate(row):
text = '`%s <%s>`_' % (col_data.text, col_data.link) if col_data.link else col_data.text
column_texts.append(text)
table_texts.append(column_texts)
# compute max length of each column so we can build the rst table
column_lengths = [len(x) for x in headers]
for column_texts in table_texts:
for i, row_text in enumerate(column_texts):
column_lengths[i] = max(column_lengths[i], len(row_text) + 2)
def get_row_limiter(char):
return ' '.join(char * length for length in column_lengths)
with file(filename, 'w') as f:
# write welcome
print >> f, '.. _plugins_index:'
print >> f
print >> f, 'List of Third-Party Plugins'
print >> f, '==========================='
print >> f
# table
print >> f, get_row_limiter('=')
for i, header in enumerate(headers):
print >> f, '{:^{fill}}'.format(header, fill=column_lengths[i]),
print >> f
print >> f, get_row_limiter('=')
for column_texts in table_texts:
for i, row_text in enumerate(column_texts):
print >> f, '{:^{fill}}'.format(row_text, fill=column_lengths[i]),
print >> f
print >> f
print >> f, get_row_limiter('=')
print >> f
print >> f, '*(Updated on %s)*' % _get_today_as_str()
#===================================================================================================
# _get_today_as_str
#===================================================================================================
def _get_today_as_str():
'''
internal. only exists so we can patch it in testing.
'''
return datetime.date.today().strftime('%Y-%m-%d')
#===================================================================================================
# generate_plugins_index
#===================================================================================================
def generate_plugins_index(client, filename):
'''
Generates an RST file with a table of the latest pytest plugins found in PyPI.
:param client: xmlrpclib.ServerProxy
:param filename: output filename
'''
plugins = get_latest_versions(iter_plugins(client))
headers, rows = obtain_plugins_table(plugins, client)
generate_plugins_index_from_table(filename, headers, rows)
#===================================================================================================
# main
#===================================================================================================
def main(argv):
filename = os.path.join(os.path.dirname(__file__), 'plugins_index.txt')
url = 'http://pypi.python.org/pypi'
parser = OptionParser(description='Generates a restructured document of pytest plugins from PyPI')
parser.add_option('-f', '--filename', default=filename, help='output filename [default: %default]')
parser.add_option('-u', '--url', default=url, help='url of PyPI server to obtain data from [default: %default]')
(options, _) = parser.parse_args(argv[1:])
client = xmlrpclib.ServerProxy(options.url)
generate_plugins_index(client, options.filename)
print 'OK'
return 0
#===================================================================================================
# main
#===================================================================================================
if __name__ == '__main__':
sys.exit(main(sys.argv))

61
doc/en/plugins_index.txt Normal file
View File

@ -0,0 +1,61 @@
.. _plugins_index:
List of Third-Party Plugins
===========================
================================================================================== ============================================================================ ==================================================================================== =============================================================================================================================================
Name Version Author Summary
================================================================================== ============================================================================ ==================================================================================== =============================================================================================================================================
`pytest-bdd <http://pypi.python.org/pypi/pytest-bdd>`_ `0.6.1 <http://pypi.python.org/pypi/pytest-bdd/0.6.1>`_ `Oleg Pidsadnyi <oleg.podsadny@gmail.com>`_ BDD for pytest
`pytest-bdd-splinter <http://pypi.python.org/pypi/pytest-bdd-splinter>`_ `0.5.2 <http://pypi.python.org/pypi/pytest-bdd-splinter/0.5.2>`_ `Oleg Pidsadnyi <oleg.podsadny@gmail.com>`_ Splinter subplugin for Pytest BDD plugin
`pytest-bench <http://pypi.python.org/pypi/pytest-bench>`_ `0.1.0 <http://pypi.python.org/pypi/pytest-bench/0.1.0>`_ `Concordus Applications <support@concordusapps.com>`_ Benchmark utility that plugs into pytest.
`pytest-blockage <http://pypi.python.org/pypi/pytest-blockage>`_ `0.1 <http://pypi.python.org/pypi/pytest-blockage/0.1>`_ `UNKNOWN <UNKNOWN>`_ Disable network requests during a test run.
`pytest-browsermob-proxy <http://pypi.python.org/pypi/pytest-browsermob-proxy>`_ `0.1 <http://pypi.python.org/pypi/pytest-browsermob-proxy/0.1>`_ `Dave Hunt <dhunt@mozilla.com>`_ BrowserMob proxy plugin for py.test.
`pytest-bugzilla <http://pypi.python.org/pypi/pytest-bugzilla>`_ `0.2 <http://pypi.python.org/pypi/pytest-bugzilla/0.2>`_ `Noufal Ibrahim <noufal@nibrahim.net.in>`_ py.test bugzilla integration plugin
`pytest-cache <http://pypi.python.org/pypi/pytest-cache>`_ `1.0 <http://pypi.python.org/pypi/pytest-cache/1.0>`_ `Holger Krekel <holger.krekel@gmail.com>`_ pytest plugin with mechanisms for caching across test runs
`pytest-capturelog <http://pypi.python.org/pypi/pytest-capturelog>`_ `0.7 <http://pypi.python.org/pypi/pytest-capturelog/0.7>`_ `Meme Dough <memedough@gmail.com>`_ py.test plugin to capture log messages
`pytest-codecheckers <http://pypi.python.org/pypi/pytest-codecheckers>`_ `0.2 <http://pypi.python.org/pypi/pytest-codecheckers/0.2>`_ `Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>`_ pytest plugin to add source code sanity checks (pep8 and friends)
`pytest-contextfixture <http://pypi.python.org/pypi/pytest-contextfixture>`_ `0.1.1 <http://pypi.python.org/pypi/pytest-contextfixture/0.1.1>`_ `Andreas Pelme <andreas@pelme.se>`_ Define pytest fixtures as context managers.
`pytest-couchdbkit <http://pypi.python.org/pypi/pytest-couchdbkit>`_ `0.5.1 <http://pypi.python.org/pypi/pytest-couchdbkit/0.5.1>`_ `RonnyPfannschmidt <ronny.pfannschmidt@gmx.de>`_ py.test extension for per-test couchdb databases using couchdbkit
`pytest-cov <http://pypi.python.org/pypi/pytest-cov>`_ `1.6 <http://pypi.python.org/pypi/pytest-cov/1.6>`_ `Meme Dough <memedough@gmail.com>`_ py.test plugin for coverage reporting with support for both centralised and distributed testing, including subprocesses and multiprocessing
`pytest-dbfixtures <http://pypi.python.org/pypi/pytest-dbfixtures>`_ `0.3.8.3 <http://pypi.python.org/pypi/pytest-dbfixtures/0.3.8.3>`_ `Clearcode - The A Room <thearoom@clearcode.cc>`_ dbfixtures plugin for py.test.
`pytest-django <http://pypi.python.org/pypi/pytest-django>`_ `2.3.1 <http://pypi.python.org/pypi/pytest-django/2.3.1>`_ `Andreas Pelme <andreas@pelme.se>`_ A Django plugin for py.test.
`pytest-django-lite <http://pypi.python.org/pypi/pytest-django-lite>`_ `0.1.0 <http://pypi.python.org/pypi/pytest-django-lite/0.1.0>`_ `David Cramer <dcramer@gmail.com>`_ The bare minimum to integrate py.test with Django.
`pytest-figleaf <http://pypi.python.org/pypi/pytest-figleaf>`_ `1.0 <http://pypi.python.org/pypi/pytest-figleaf/1.0>`_ `holger krekel <py-dev@codespeak.net,holger@merlinux.eu>`_ py.test figleaf coverage plugin
`pytest-flakes <http://pypi.python.org/pypi/pytest-flakes>`_ `0.2 <http://pypi.python.org/pypi/pytest-flakes/0.2>`_ `Florian Schulze, Holger Krekel and Ronny Pfannschmidt <florian.schulze@gmx.net>`_ pytest plugin to check source code with pyflakes
`pytest-greendots <http://pypi.python.org/pypi/pytest-greendots>`_ `0.2 <http://pypi.python.org/pypi/pytest-greendots/0.2>`_ `UNKNOWN <UNKNOWN>`_ Green progress dots
`pytest-growl <http://pypi.python.org/pypi/pytest-growl>`_ `0.1 <http://pypi.python.org/pypi/pytest-growl/0.1>`_ `Anthony Long <antlong@gmail.com>`_ Growl notifications for pytest results.
`pytest-incremental <http://pypi.python.org/pypi/pytest-incremental>`_ `0.3.0 <http://pypi.python.org/pypi/pytest-incremental/0.3.0>`_ `Eduardo Naufel Schettino <schettino72@gmail.com>`_ an incremental test runner (pytest plugin)
`pytest-instafail <http://pypi.python.org/pypi/pytest-instafail>`_ `0.1.0 <http://pypi.python.org/pypi/pytest-instafail/0.1.0>`_ `Janne Vanhala <janne.vanhala@gmail.com>`_ py.test plugin to show failures instantly
`pytest-ipdb <http://pypi.python.org/pypi/pytest-ipdb>`_ `0.1-prerelease <http://pypi.python.org/pypi/pytest-ipdb/0.1-prerelease>`_ `Matthew de Verteuil <onceuponajooks@gmail.com>`_ A py.test plug-in to enable drop to ipdb debugger on test failure.
`pytest-konira <http://pypi.python.org/pypi/pytest-konira>`_ `0.2 <http://pypi.python.org/pypi/pytest-konira/0.2>`_ `Alfredo Deza <alfredodeza [at] gmail.com>`_ Run Konira DSL tests with py.test
`pytest-localserver <http://pypi.python.org/pypi/pytest-localserver>`_ `0.3 <http://pypi.python.org/pypi/pytest-localserver/0.3>`_ `Sebastian Rahlf <basti AT redtoad DOT de>`_ py.test plugin to test server connections locally.
`pytest-marker-bugzilla <http://pypi.python.org/pypi/pytest-marker-bugzilla>`_ `0.06 <http://pypi.python.org/pypi/pytest-marker-bugzilla/0.06>`_ `Eric Sammons <elsammons@gmail.com>`_ py.test bugzilla integration plugin, using markers
`pytest-markfiltration <http://pypi.python.org/pypi/pytest-markfiltration>`_ `0.8 <http://pypi.python.org/pypi/pytest-markfiltration/0.8>`_ `adam goucher <adam@element34.ca>`_ UNKNOWN
`pytest-marks <http://pypi.python.org/pypi/pytest-marks>`_ `0.4 <http://pypi.python.org/pypi/pytest-marks/0.4>`_ `adam goucher <adam@element34.ca>`_ UNKNOWN
`pytest-monkeyplus <http://pypi.python.org/pypi/pytest-monkeyplus>`_ `1.1.0 <http://pypi.python.org/pypi/pytest-monkeyplus/1.1.0>`_ `Virgil Dupras <hsoft@hardcoded.net>`_ pytest's monkeypatch subclass with extra functionalities
`pytest-mozwebqa <http://pypi.python.org/pypi/pytest-mozwebqa>`_ `1.1.1 <http://pypi.python.org/pypi/pytest-mozwebqa/1.1.1>`_ `Dave Hunt <dhunt@mozilla.com>`_ Mozilla WebQA plugin for py.test.
`pytest-oerp <http://pypi.python.org/pypi/pytest-oerp>`_ `0.2.0 <http://pypi.python.org/pypi/pytest-oerp/0.2.0>`_ `Leonardo Santagada <santagada@gmail.com>`_ pytest plugin to test OpenERP modules
`pytest-osxnotify <http://pypi.python.org/pypi/pytest-osxnotify>`_ `0.1.4 <http://pypi.python.org/pypi/pytest-osxnotify/0.1.4>`_ `Daniel Bader <mail@dbader.org>`_ OS X notifications for py.test results.
`pytest-paste-config <http://pypi.python.org/pypi/pytest-paste-config>`_ `0.1 <http://pypi.python.org/pypi/pytest-paste-config/0.1>`_ `UNKNOWN <UNKNOWN>`_ Allow setting the path to a paste config file
`pytest-pep8 <http://pypi.python.org/pypi/pytest-pep8>`_ `1.0.5 <http://pypi.python.org/pypi/pytest-pep8/1.0.5>`_ `Holger Krekel and Ronny Pfannschmidt <holger.krekel@gmail.com>`_ pytest plugin to check PEP8 requirements
`pytest-poo <http://pypi.python.org/pypi/pytest-poo>`_ `0.2 <http://pypi.python.org/pypi/pytest-poo/0.2>`_ `Andreas Pelme <andreas@pelme.se>`_ Visualize your crappy tests
`pytest-pydev <http://pypi.python.org/pypi/pytest-pydev>`_ `0.1 <http://pypi.python.org/pypi/pytest-pydev/0.1>`_ `Sebastian Rahlf <basti AT redtoad DOT de>`_ py.test plugin to connect to a remote debug server with PyDev or PyCharm.
`pytest-qt <http://pypi.python.org/pypi/pytest-qt>`_ `1.0.2 <http://pypi.python.org/pypi/pytest-qt/1.0.2>`_ `Bruno Oliveira <nicoddemus@gmail.com>`_ pytest plugin that adds fixtures for testing Qt (PyQt and PySide) applications.
`pytest-quickcheck <http://pypi.python.org/pypi/pytest-quickcheck>`_ `0.7 <http://pypi.python.org/pypi/pytest-quickcheck/0.7>`_ `Tetsuya Morimoto <tetsuya dot morimoto at gmail dot com>`_ pytest plugin to generate random data inspired by QuickCheck
`pytest-rage <http://pypi.python.org/pypi/pytest-rage>`_ `0.1 <http://pypi.python.org/pypi/pytest-rage/0.1>`_ `Leonardo Santagada <santagada@gmail.com>`_ pytest plugin to implement PEP712
`pytest-random <http://pypi.python.org/pypi/pytest-random>`_ `0.02 <http://pypi.python.org/pypi/pytest-random/0.02>`_ `Leah Klearman <lklrmn@gmail.com>`_ py.test plugin to randomize tests
`pytest-rerunfailures <http://pypi.python.org/pypi/pytest-rerunfailures>`_ `0.03 <http://pypi.python.org/pypi/pytest-rerunfailures/0.03>`_ `Leah Klearman <lklrmn@gmail.com>`_ py.test plugin to re-run tests to eliminate flakey failures
`pytest-runfailed <http://pypi.python.org/pypi/pytest-runfailed>`_ `0.3 <http://pypi.python.org/pypi/pytest-runfailed/0.3>`_ `Dimitri Merejkowsky <d.merej@gmail.com>`_ implement a --failed option for pytest
`pytest-runner <http://pypi.python.org/pypi/pytest-runner>`_ `2.0 <http://pypi.python.org/pypi/pytest-runner/2.0>`_ `Jason R. Coombs <jaraco@jaraco.com>`_ UNKNOWN
`pytest-sugar <http://pypi.python.org/pypi/pytest-sugar>`_ `0.2.2 <http://pypi.python.org/pypi/pytest-sugar/0.2.2>`_ `Teemu, Janne Vanhala <orkkiolento@gmail.com, janne.vanhala@gmail.com>`_ py.test plugin that adds instafail, ETA and neat graphics
`pytest-timeout <http://pypi.python.org/pypi/pytest-timeout>`_ `0.3 <http://pypi.python.org/pypi/pytest-timeout/0.3>`_ `Floris Bruynooghe <flub@devork.be>`_ pytest plugin to abort tests after a timeout
`pytest-twisted <http://pypi.python.org/pypi/pytest-twisted>`_ `1.4 <http://pypi.python.org/pypi/pytest-twisted/1.4>`_ `Ralf Schmitt <ralf@brainbot.com>`_ A twisted plugin for py.test.
`pytest-xdist <http://pypi.python.org/pypi/pytest-xdist>`_ `1.9 <http://pypi.python.org/pypi/pytest-xdist/1.9>`_ `holger krekel and contributors <pytest-dev@python.org,holger@merlinux.eu>`_ py.test xdist plugin for distributed testing and loop-on-failing modes
`pytest-xprocess <http://pypi.python.org/pypi/pytest-xprocess>`_ `0.8 <http://pypi.python.org/pypi/pytest-xprocess/0.8>`_ `Holger Krekel <holger@merlinux.eu>`_ pytest plugin to manage external processes across test runs
`pytest-yamlwsgi <http://pypi.python.org/pypi/pytest-yamlwsgi>`_ `0.6 <http://pypi.python.org/pypi/pytest-yamlwsgi/0.6>`_ `Ali Afshar <aafshar@gmail.com>`_ Run tests against wsgi apps defined in yaml
`pytest-zap <http://pypi.python.org/pypi/pytest-zap>`_ `0.1 <http://pypi.python.org/pypi/pytest-zap/0.1>`_ `Dave Hunt <dhunt@mozilla.com>`_ OWASP ZAP plugin for py.test.
================================================================================== ============================================================================ ==================================================================================== =============================================================================================================================================
*(Updated on 2013-10-11)*

View File

@ -0,0 +1,88 @@
import os
import xmlrpclib
#===================================================================================================
# test_plugins_index
#===================================================================================================
def test_plugins_index(tmpdir, monkeypatch):
'''
Blackbox testing for plugins_index script. Calls main() generating a file and compares produced
output to expected.
.. note:: if the test fails, a file named `test_plugins_index.obtained` will be generated in
the same directory as this test file. Ensure the contents are correct and overwrite
the global `expected_output` with the new contents.
'''
import plugins_index
# dummy interface to xmlrpclib.ServerProxy
class DummyProxy(object):
expected_url = 'http://dummy.pypi'
def __init__(self, url):
assert url == self.expected_url
def search(self, query):
assert query == {'name' : 'pytest-'}
return [
{'name': 'pytest-plugin1', 'version' : '0.8'},
{'name': 'pytest-plugin1', 'version' : '1.0'},
{'name': 'pytest-plugin2', 'version' : '1.2'},
]
def release_data(self, package_name, version):
results = {
('pytest-plugin1', '1.0') : {
'package_url' : 'http://plugin1',
'release_url' : 'http://plugin1/1.0',
'author' : 'someone',
'author_email' : 'someone@py.com',
'summary' : 'some plugin',
},
('pytest-plugin2', '1.2') : {
'package_url' : 'http://plugin2',
'release_url' : 'http://plugin2/1.2',
'author' : 'other',
'author_email' : 'other@py.com',
'summary' : 'some other plugin',
},
}
return results[(package_name, version)]
monkeypatch.setattr(xmlrpclib, 'ServerProxy', DummyProxy, 'foo')
monkeypatch.setattr(plugins_index, '_get_today_as_str', lambda: '2013-10-20')
output_file = str(tmpdir.join('output.txt'))
assert plugins_index.main(['', '-f', output_file, '-u', DummyProxy.expected_url]) == 0
with file(output_file, 'rU') as f:
obtained_output = f.read()
if obtained_output != expected_output:
obtained_file = os.path.splitext(__file__)[0] + '.obtained'
with file(obtained_file, 'w') as f:
f.write(obtained_output)
assert obtained_output == expected_output
expected_output = '''\
.. _plugins_index:
List of Third-Party Plugins
===========================
==================================== ============================= ============================= ===================
Name Version Author Summary
==================================== ============================= ============================= ===================
`pytest-plugin1 <http://plugin1>`_ `1.0 <http://plugin1/1.0>`_ `someone <someone@py.com>`_ some plugin
`pytest-plugin2 <http://plugin2>`_ `1.2 <http://plugin2/1.2>`_ `other <other@py.com>`_ some other plugin
==================================== ============================= ============================= ===================
*(Updated on 2013-10-20)*
'''