summaryrefslogtreecommitdiff
path: root/doc/en/plugins_index.py
blob: 0e6caa1ec46b47161a07673acccf3c5e073a2774 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
'''
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
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, '*(Last updated: %s)*' % 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):
    client = xmlrpclib.ServerProxy('http://pypi.python.org/pypi')
    filename = os.path.join(os.path.dirname(__file__), 'plugins_index.txt')
    generate_plugins_index(client, filename)
    print 'OK'
    return 0

#===================================================================================================
# main
#===================================================================================================
if __name__ == '__main__':
    sys.exit(main(sys.argv))