Skip to content

Commit cad1de2

Browse files
TomDLTqinhanmin2014
authored andcommitted
MNT Generate emeritus list, add dates, and change sorting (scikit-learn#13586)
1 parent 250de78 commit cad1de2

File tree

5 files changed

+159
-90
lines changed

5 files changed

+159
-90
lines changed

build_tools/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Makefile for maintenance tools
22

33
authors:
4-
python generate_authors_table.py > ../doc/authors.rst
4+
python generate_authors_table.py

build_tools/generate_authors_table.py

+111-49
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import sys
1010
import requests
1111
import getpass
12+
import time
1213

13-
# With authentication: up to 5000 requests per hour.
1414
print("user:", file=sys.stderr)
1515
user = input()
1616
passwd = getpass.getpass("Password or access token:\n")
@@ -20,6 +20,20 @@
2020
LOGO_URL = 'https://avatars2.githubusercontent.com/u/365630?v=4'
2121

2222

23+
def get(url):
24+
for sleep_time in [10, 30, 0]:
25+
reply = requests.get(url, auth=auth)
26+
api_limit = ("message" in reply.json()
27+
and "API rate limit exceeded" in reply.json()["message"])
28+
if not api_limit:
29+
break
30+
print("API rate limit exceeded, waiting..")
31+
time.sleep(sleep_time)
32+
33+
reply.raise_for_status()
34+
return reply
35+
36+
2337
def group_iterable(iterable, size):
2438
"""Group iterable into lines"""
2539
group = []
@@ -34,73 +48,121 @@ def group_iterable(iterable, size):
3448

3549
def get_contributors():
3650
"""Get the list of contributor profiles. Require admin rights."""
37-
# get members of scikit-learn teams on GitHub
38-
members = []
51+
# get members of scikit-learn core-dev on GitHub
52+
core_devs = []
3953
team = 11523
4054
for page in [1, 2]: # 30 per page
41-
reply = requests.get(
42-
"https://api.github.com/teams/%d/members?page=%d"
43-
% (team, page), auth=auth)
44-
reply.raise_for_status()
55+
reply = get("https://api.github.com/teams/%d/members?page=%d" %
56+
(team, page))
57+
core_devs.extend(reply.json())
58+
59+
# get members of scikit-learn on GitHub
60+
members = []
61+
for page in [1, 2]: # 30 per page
62+
reply = get(
63+
"https://api.github.com/orgs/scikit-learn/members?page=%d" %
64+
(page, ))
4565
members.extend(reply.json())
4666

4767
# keep only the logins
48-
logins = [c['login'] for c in members]
49-
# remove duplicate
50-
logins = set(logins)
68+
core_devs = [c['login'] for c in core_devs]
69+
members = [c['login'] for c in members]
70+
71+
# add missing contributors with GitHub accounts
72+
members.extend(['dubourg', 'mbrucher', 'thouis', 'jarrodmillman'])
73+
# add missing contributors without GitHub accounts
74+
members.extend(['Angel Soler Gollonet'])
75+
# remove CI bots
76+
members.remove('sklearn-ci')
77+
members.remove('sklearn-lgtm')
78+
members.remove('sklearn-wheels')
79+
80+
# remove duplicate, and get the difference of the two sets
81+
core_devs = set(core_devs)
82+
members = set(members)
83+
emeritus = members.difference(core_devs)
5184

5285
# get profiles from GitHub
53-
profiles = [get_profile(login) for login in logins]
86+
core_devs = [get_profile(login) for login in core_devs]
87+
emeritus = [get_profile(login) for login in emeritus]
88+
5489
# sort by last name
55-
profiles = sorted(profiles, key=key)
90+
core_devs = sorted(core_devs, key=key)
91+
emeritus = sorted(emeritus, key=key)
5692

57-
return profiles
93+
return core_devs, emeritus
5894

5995

6096
def get_profile(login):
6197
"""Get the GitHub profile from login"""
62-
profile = requests.get("https://api.github.com/users/%s" % login,
63-
auth=auth).json()
64-
if 'name' not in profile:
65-
# default profile if the login does not exist
98+
print("get profile for %s" % (login, ))
99+
try:
100+
profile = get("https://api.github.com/users/%s" % login).json()
101+
except requests.exceptions.HTTPError:
66102
return dict(name=login, avatar_url=LOGO_URL, html_url="")
67-
else:
68-
if profile["name"] is None:
69-
profile["name"] = profile["login"]
70103

71-
# fix missing names
72-
missing_names = {'bthirion': 'Bertrand Thirion',
73-
'Duchesnay': 'Edouard Duchesnay',
74-
'Lars': 'Lars Buitinck',
75-
'MechCoder': 'Manoj Kumar'}
76-
if profile["name"] in missing_names:
77-
profile["name"] = missing_names[profile["name"]]
78-
return profile
104+
if profile["name"] is None:
105+
profile["name"] = profile["login"]
106+
107+
# fix missing names
108+
missing_names = {
109+
'bthirion': 'Bertrand Thirion',
110+
'dubourg': 'Vincent Dubourg',
111+
'Duchesnay': 'Edouard Duchesnay',
112+
'Lars': 'Lars Buitinck',
113+
'MechCoder': 'Manoj Kumar',
114+
'jeremiedbb': 'Jérémie Du Boisberranger',
115+
}
116+
if profile["name"] in missing_names:
117+
profile["name"] = missing_names[profile["name"]]
118+
119+
return profile
79120

80121

81122
def key(profile):
82123
"""Get the last name in lower case"""
83124
return profile["name"].split(' ')[-1].lower()
84125

85126

86-
contributors = get_contributors()
87-
88-
print(".. raw :: html\n")
89-
print(" <!-- Generated by generate_authors_table.py -->")
90-
print(" <table>")
91-
print(" <col style='width:%d%%' span='%d'>"
92-
% (int(100 / ROW_SIZE), ROW_SIZE))
93-
print(" <style>")
94-
print(" img.avatar {border-radius: 10px;}")
95-
print(" td {vertical-align: top;}")
96-
print(" </style>")
97-
for row in group_iterable(contributors, size=ROW_SIZE):
98-
print(" <tr>")
99-
for contributor in row:
100-
print(" <td>")
101-
print(" <a href='%s'><img src='%s' class='avatar' /></a> <br />"
102-
% (contributor["html_url"], contributor["avatar_url"]))
103-
print(" <p>%s</p>" % contributor["name"])
104-
print(" </td>")
105-
print(" </tr>")
106-
print(" </table>")
127+
def generate_table(contributors):
128+
lines = [
129+
(".. raw :: html\n"),
130+
(" <!-- Generated by generate_authors_table.py -->"),
131+
(" <table>"),
132+
(" <col style='width:%d%%' span='%d'>" %
133+
(int(100 / ROW_SIZE), ROW_SIZE)),
134+
(" <style>"),
135+
(" img.avatar {border-radius: 10px;}"),
136+
(" td {vertical-align: top;}"),
137+
(" </style>"),
138+
]
139+
for row in group_iterable(contributors, size=ROW_SIZE):
140+
lines.append(" <tr>")
141+
for contributor in row:
142+
lines.append(" <td>")
143+
lines.append(
144+
" <a href='%s'><img src='%s' class='avatar' /></a> <br />" %
145+
(contributor["html_url"], contributor["avatar_url"]))
146+
lines.append(" <p>%s</p>" % (contributor["name"], ))
147+
lines.append(" </td>")
148+
lines.append(" </tr>")
149+
lines.append(" </table>")
150+
return '\n'.join(lines)
151+
152+
153+
def generate_list(contributors):
154+
lines = []
155+
for contributor in contributors:
156+
lines.append("- %s" % (contributor["name"], ))
157+
return '\n'.join(lines)
158+
159+
160+
if __name__ == "__main__":
161+
162+
core_devs, emeritus = get_contributors()
163+
164+
with open("../doc/authors.rst", "w+") as rst_file:
165+
rst_file.write(generate_table(core_devs))
166+
167+
with open("../doc/authors_emeritus.rst", "w+") as rst_file:
168+
rst_file.write(generate_list(emeritus))

doc/about.rst

+5-35
Original file line numberDiff line numberDiff line change
@@ -40,41 +40,11 @@ in the FAQ.
4040

4141
Emeritus Core Developers
4242
------------------------
43-
The following people have been active contributors in the past, but are no longer active in the project
44-
45-
46-
- Alexander Fabisch
47-
- Alexandre Passos
48-
- Angel Soler Gollonet
49-
- Arnaud Joly
50-
- Chris Gorgolewski
51-
- David Cournapeau
52-
- David Warde-Farley
53-
- Eduard Duchesnay
54-
- Fabian Pedragosa
55-
- Gilles Louppe
56-
- Jacob Schreiber
57-
- Jake Vanderplas
58-
- Jaques Grobler
59-
- Jarrod Millman
60-
- Kyle Kastner
61-
- Lars Buitinck
62-
- Manoj Kumar
63-
- Mathieu Blondel
64-
- Matthieu Brucher
65-
- Noel Dawe
66-
- Paolo Losi
67-
- Peter Prettenhofer
68-
- Raghav Rajagopalan
69-
- Robert Layton
70-
- Ron Weiss
71-
- Satrajit Ghosh
72-
- Shiqiao Du
73-
- Thouis (Ray) Jones
74-
- Vincent Dubourg
75-
- Vincent Michel
76-
- Virgile Fritsch
77-
- Wei Li
43+
The following people have been active contributors in the past, but are no
44+
longer active in the project:
45+
46+
.. include:: authors_emeritus.rst
47+
7848

7949
.. _citing-scikit-learn:
8050

doc/authors.rst

+9-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
</style>
1010
<tr>
1111
<td>
12+
<a href='https://github.com/jeremiedbb'><img src='https://avatars2.githubusercontent.com/u/34657725?v=4' class='avatar' /></a> <br />
13+
<p>Jérémie Du Boisberranger</p>
14+
</td>
15+
<td>
1216
<a href='https://github.com/jorisvandenbossche'><img src='https://avatars2.githubusercontent.com/u/1020496?v=4' class='avatar' /></a> <br />
1317
<p>Joris Van den Bossche</p>
1418
</td>
@@ -32,12 +36,12 @@
3236
<a href='https://github.com/yarikoptic'><img src='https://avatars3.githubusercontent.com/u/39889?v=4' class='avatar' /></a> <br />
3337
<p>Yaroslav Halchenko</p>
3438
</td>
39+
</tr>
40+
<tr>
3541
<td>
3642
<a href='https://github.com/NicolasHug'><img src='https://avatars2.githubusercontent.com/u/1190450?v=4' class='avatar' /></a> <br />
3743
<p>Nicolas Hug</p>
3844
</td>
39-
</tr>
40-
<tr>
4145
<td>
4246
<a href='https://github.com/adrinjalali'><img src='https://avatars3.githubusercontent.com/u/1663864?v=4' class='avatar' /></a> <br />
4347
<p>Adrin Jalali</p>
@@ -62,12 +66,12 @@
6266
<a href='https://github.com/jnothman'><img src='https://avatars2.githubusercontent.com/u/78827?v=4' class='avatar' /></a> <br />
6367
<p>Joel Nothman</p>
6468
</td>
69+
</tr>
70+
<tr>
6571
<td>
6672
<a href='https://github.com/qinhanmin2014'><img src='https://avatars2.githubusercontent.com/u/12003569?v=4' class='avatar' /></a> <br />
6773
<p>Hanmin Qin</p>
6874
</td>
69-
</tr>
70-
<tr>
7175
<td>
7276
<a href='https://github.com/bthirion'><img src='https://avatars1.githubusercontent.com/u/234454?v=4' class='avatar' /></a> <br />
7377
<p>Bertrand Thirion</p>
@@ -89,4 +93,4 @@
8993
<p>Roman Yurchak</p>
9094
</td>
9195
</tr>
92-
</table>
96+
</table>

doc/authors_emeritus.rst

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
- Mathieu Blondel
2+
- Matthieu Brucher
3+
- Lars Buitinck
4+
- David Cournapeau
5+
- Noel Dawe
6+
- Shiqiao Du
7+
- Vincent Dubourg
8+
- Edouard Duchesnay
9+
- Alexander Fabisch
10+
- Virgile Fritsch
11+
- Satrajit Ghosh
12+
- Angel Soler Gollonet
13+
- Chris Gorgolewski
14+
- Jaques Grobler
15+
- Brian Holt
16+
- Arnaud Joly
17+
- Thouis (Ray) Jones
18+
- Kyle Kastner
19+
- Manoj Kumar
20+
- Robert Layton
21+
- Wei Li
22+
- Paolo Losi
23+
- Gilles Louppe
24+
- Vincent Michel
25+
- Jarrod Millman
26+
- Alexandre Passos
27+
- Fabian Pedregosa
28+
- Peter Prettenhofer
29+
- (Venkat) Raghav, Rajagopalan
30+
- Jacob Schreiber
31+
- Jake Vanderplas
32+
- David Warde-Farley
33+
- Ron Weiss

0 commit comments

Comments
 (0)