1
1
#!/usr/bin/env python3
2
2
"""Update and sort the creators list of the zenodo record."""
3
+ import json
3
4
import sys
4
5
from pathlib import Path
5
- import json
6
+
6
7
import click
7
8
from fuzzywuzzy import fuzz , process
8
9
@@ -35,44 +36,35 @@ def read_md_table(md_text):
35
36
keys = None
36
37
retval = []
37
38
for line in md_text .splitlines ():
38
- if line .strip ().startswith ("| --- |" ):
39
- keys = (
40
- k .replace ("*" , "" ).strip ()
41
- for k in prev .split ("|" )
42
- )
39
+ if line .strip ().startswith ('| --- |' ):
40
+ keys = (k .replace ('*' , '' ).strip () for k in prev .split ('|' ))
43
41
keys = [k .lower () for k in keys if k ]
44
42
continue
45
43
elif not keys :
46
44
prev = line
47
45
continue
48
46
49
- if not line or not line .strip ().startswith ("|" ):
47
+ if not line or not line .strip ().startswith ('|' ):
50
48
break
51
49
52
- values = [v .strip () or None for v in line .split ("|" )][1 :- 1 ]
53
- retval .append ({k : v for k , v in zip (keys , values ) if v })
50
+ values = [v .strip () or None for v in line .split ('|' )][1 :- 1 ]
51
+ retval .append ({k : v for k , v in zip (keys , values , strict = False ) if v })
54
52
55
53
return retval
56
54
57
55
58
56
def sort_contributors (entries , git_lines , exclude = None , last = None ):
59
57
"""Return a list of author dictionaries, ordered by contribution."""
60
58
last = last or []
61
- sorted_authors = sorted (entries , key = lambda i : i [" name" ])
59
+ sorted_authors = sorted (entries , key = lambda i : i [' name' ])
62
60
63
- first_last = [
64
- " " .join (val ["name" ].split ("," )[::- 1 ]).strip () for val in sorted_authors
65
- ]
66
- first_last_excl = [
67
- " " .join (val ["name" ].split ("," )[::- 1 ]).strip () for val in exclude or []
68
- ]
61
+ first_last = [' ' .join (val ['name' ].split (',' )[::- 1 ]).strip () for val in sorted_authors ]
62
+ first_last_excl = [' ' .join (val ['name' ].split (',' )[::- 1 ]).strip () for val in exclude or []]
69
63
70
64
unmatched = []
71
65
author_matches = []
72
66
for ele in git_lines :
73
- matches = process .extract (
74
- ele , first_last , scorer = fuzz .token_sort_ratio , limit = 2
75
- )
67
+ matches = process .extract (ele , first_last , scorer = fuzz .token_sort_ratio , limit = 2 )
76
68
# matches is a list [('First match', % Match), ('Second match', % Match)]
77
69
if matches [0 ][1 ] > 80 :
78
70
val = sorted_authors [first_last .index (matches [0 ][0 ])]
@@ -85,15 +77,15 @@ def sort_contributors(entries, git_lines, exclude=None, last=None):
85
77
if val not in author_matches :
86
78
author_matches .append (val )
87
79
88
- names = {" " .join (val [" name" ].split ("," )[::- 1 ]).strip () for val in author_matches }
80
+ names = {' ' .join (val [' name' ].split (',' )[::- 1 ]).strip () for val in author_matches }
89
81
for missing_name in first_last :
90
82
if missing_name not in names :
91
83
missing = sorted_authors [first_last .index (missing_name )]
92
84
author_matches .append (missing )
93
85
94
86
position_matches = []
95
87
for i , item in enumerate (author_matches ):
96
- pos = item .pop (" position" , None )
88
+ pos = item .pop (' position' , None )
97
89
if pos is not None :
98
90
position_matches .append ((i , int (pos )))
99
91
@@ -105,7 +97,7 @@ def sort_contributors(entries, git_lines, exclude=None, last=None):
105
97
return author_matches , unmatched
106
98
107
99
108
- def get_git_lines (fname = " line-contributors.txt" ):
100
+ def get_git_lines (fname = ' line-contributors.txt' ):
109
101
"""Run git-line-summary."""
110
102
import shutil
111
103
import subprocess as sp
@@ -114,15 +106,15 @@ def get_git_lines(fname="line-contributors.txt"):
114
106
115
107
lines = []
116
108
if contrib_file .exists ():
117
- print (" WARNING: Reusing existing line-contributors.txt file." , file = sys .stderr )
109
+ print (' WARNING: Reusing existing line-contributors.txt file.' , file = sys .stderr )
118
110
lines = contrib_file .read_text ().splitlines ()
119
111
120
- git_line_summary_path = shutil .which (" git-line-summary" )
112
+ git_line_summary_path = shutil .which (' git-line-summary' )
121
113
if not lines and git_line_summary_path :
122
- print (" Running git-line-summary on repo" )
114
+ print (' Running git-line-summary on repo' )
123
115
lines = sp .check_output ([git_line_summary_path ]).decode ().splitlines ()
124
- lines = [line for line in lines if " Not Committed Yet" not in line ]
125
- contrib_file .write_text (" \n " .join (lines ))
116
+ lines = [line for line in lines if ' Not Committed Yet' not in line ]
117
+ contrib_file .write_text (' \n ' .join (lines ))
126
118
127
119
if not lines :
128
120
raise RuntimeError (
@@ -132,13 +124,13 @@ def get_git_lines(fname="line-contributors.txt"):
132
124
git-line-summary not found, please install git-extras. """
133
125
* (git_line_summary_path is None )
134
126
)
135
- return [" " .join (line .strip ().split ()[1 :- 1 ]) for line in lines if "%" in line ]
127
+ return [' ' .join (line .strip ().split ()[1 :- 1 ]) for line in lines if '%' in line ]
136
128
137
129
138
130
def _namelast (inlist ):
139
131
retval = []
140
132
for i in inlist :
141
- i [" name" ] = (f"{ i .pop ('name' , '' )} { i .pop ('lastname' , '' )} " ).strip ()
133
+ i [' name' ] = (f"{ i .pop ('name' , '' )} { i .pop ('lastname' , '' )} " ).strip ()
142
134
retval .append (i )
143
135
return retval
144
136
@@ -150,12 +142,13 @@ def cli():
150
142
151
143
152
144
@cli .command ()
153
- @click .option ("-z" , "--zenodo-file" , type = click .Path (exists = True ), default = ".zenodo.json" )
154
- @click .option ("-m" , "--maintainers" , type = click .Path (exists = True ), default = ".maint/MAINTAINERS.md" )
155
- @click .option ("-c" , "--contributors" , type = click .Path (exists = True ),
156
- default = ".maint/CONTRIBUTORS.md" )
157
- @click .option ("--pi" , type = click .Path (exists = True ), default = ".maint/PIs.md" )
158
- @click .option ("-f" , "--former-file" , type = click .Path (exists = True ), default = ".maint/FORMER.md" )
145
+ @click .option ('-z' , '--zenodo-file' , type = click .Path (exists = True ), default = '.zenodo.json' )
146
+ @click .option ('-m' , '--maintainers' , type = click .Path (exists = True ), default = '.maint/MAINTAINERS.md' )
147
+ @click .option (
148
+ '-c' , '--contributors' , type = click .Path (exists = True ), default = '.maint/CONTRIBUTORS.md'
149
+ )
150
+ @click .option ('--pi' , type = click .Path (exists = True ), default = '.maint/PIs.md' )
151
+ @click .option ('-f' , '--former-file' , type = click .Path (exists = True ), default = '.maint/FORMER.md' )
159
152
def zenodo (
160
153
zenodo_file ,
161
154
maintainers ,
@@ -176,65 +169,60 @@ def zenodo(
176
169
)
177
170
178
171
zen_contributors , miss_contributors = sort_contributors (
179
- _namelast (read_md_table (Path (contributors ).read_text ())),
180
- data ,
181
- exclude = former
172
+ _namelast (read_md_table (Path (contributors ).read_text ())), data , exclude = former
182
173
)
183
174
184
175
zen_pi = _namelast (
185
176
sorted (
186
177
read_md_table (Path (pi ).read_text ()),
187
- key = lambda v : (int (v .get (" position" , - 1 )), v .get (" lastname" ))
178
+ key = lambda v : (int (v .get (' position' , - 1 )), v .get (' lastname' )),
188
179
)
189
180
)
190
181
191
- zenodo [" creators" ] = zen_creators
192
- zenodo [" contributors" ] = zen_contributors + zen_pi
182
+ zenodo [' creators' ] = zen_creators
183
+ zenodo [' contributors' ] = zen_contributors + zen_pi
193
184
194
185
misses = set (miss_creators ).intersection (miss_contributors )
195
186
if misses :
196
187
print (
197
- "Some people made commits, but are missing in .maint/ "
198
- f"files: { ', ' .join (misses )} " ,
188
+ "Some people made commits, but are missing in .maint/ " f"files: { ', ' .join (misses )} " ,
199
189
file = sys .stderr ,
200
190
)
201
191
202
192
# Remove position
203
- for creator in zenodo ["creators" ]:
204
- creator .pop ("position" , None )
205
- creator .pop ("handle" , None )
206
- if isinstance (creator ["affiliation" ], list ):
207
- creator ["affiliation" ] = creator ["affiliation" ][0 ]
208
-
209
- for creator in zenodo ["contributors" ]:
210
- creator .pop ("handle" , None )
211
- creator ["type" ] = "Researcher"
212
- creator .pop ("position" , None )
213
-
214
- if isinstance (creator ["affiliation" ], list ):
215
- creator ["affiliation" ] = creator ["affiliation" ][0 ]
216
-
217
- Path (zenodo_file ).write_text (
218
- "%s\n " % json .dumps (zenodo , indent = 2 )
219
- )
193
+ for creator in zenodo ['creators' ]:
194
+ creator .pop ('position' , None )
195
+ creator .pop ('handle' , None )
196
+ if isinstance (creator ['affiliation' ], list ):
197
+ creator ['affiliation' ] = creator ['affiliation' ][0 ]
198
+
199
+ for creator in zenodo ['contributors' ]:
200
+ creator .pop ('handle' , None )
201
+ creator ['type' ] = 'Researcher'
202
+ creator .pop ('position' , None )
203
+
204
+ if isinstance (creator ['affiliation' ], list ):
205
+ creator ['affiliation' ] = creator ['affiliation' ][0 ]
206
+
207
+ Path (zenodo_file ).write_text ('%s\n ' % json .dumps (zenodo , indent = 2 ))
220
208
221
209
222
210
@cli .command ()
223
- @click .option ("-m" , "--maintainers" , type = click .Path (exists = True ), default = ".maint/MAINTAINERS.md" )
224
- @click .option ("-c" , "--contributors" , type = click .Path (exists = True ),
225
- default = ".maint/CONTRIBUTORS.md" )
226
- @click .option ("--pi" , type = click .Path (exists = True ), default = ".maint/PIs.md" )
227
- @click .option ("-f" , "--former-file" , type = click .Path (exists = True ), default = ".maint/FORMER.md" )
211
+ @click .option ('-m' , '--maintainers' , type = click .Path (exists = True ), default = '.maint/MAINTAINERS.md' )
212
+ @click .option (
213
+ '-c' , '--contributors' , type = click .Path (exists = True ), default = '.maint/CONTRIBUTORS.md'
214
+ )
215
+ @click .option ('--pi' , type = click .Path (exists = True ), default = '.maint/PIs.md' )
216
+ @click .option ('-f' , '--former-file' , type = click .Path (exists = True ), default = '.maint/FORMER.md' )
228
217
def publication (
229
218
maintainers ,
230
219
contributors ,
231
220
pi ,
232
221
former_file ,
233
222
):
234
223
"""Generate the list of authors and affiliations for papers."""
235
- members = (
236
- _namelast (read_md_table (Path (maintainers ).read_text ()))
237
- + _namelast (read_md_table (Path (contributors ).read_text ()))
224
+ members = _namelast (read_md_table (Path (maintainers ).read_text ())) + _namelast (
225
+ read_md_table (Path (contributors ).read_text ())
238
226
)
239
227
240
228
hits , misses = sort_contributors (
@@ -246,15 +234,12 @@ def publication(
246
234
pi_hits = _namelast (
247
235
sorted (
248
236
read_md_table (Path (pi ).read_text ()),
249
- key = lambda v : (int (v .get (" position" , - 1 )), v .get (" lastname" ))
237
+ key = lambda v : (int (v .get (' position' , - 1 )), v .get (' lastname' )),
250
238
)
251
239
)
252
240
253
- pi_names = [pi ["name" ] for pi in pi_hits ]
254
- hits = [
255
- hit for hit in hits
256
- if hit ["name" ] not in pi_names
257
- ] + pi_hits
241
+ pi_names = [pi ['name' ] for pi in pi_hits ]
242
+ hits = [hit for hit in hits if hit ['name' ] not in pi_names ] + pi_hits
258
243
259
244
def _aslist (value ):
260
245
if isinstance (value , (list , tuple )):
@@ -264,47 +249,39 @@ def _aslist(value):
264
249
# Remove position
265
250
affiliations = []
266
251
for item in hits :
267
- item .pop (" position" , None )
268
- for a in _aslist (item .get (" affiliation" , " Unaffiliated" )):
252
+ item .pop (' position' , None )
253
+ for a in _aslist (item .get (' affiliation' , ' Unaffiliated' )):
269
254
if a not in affiliations :
270
255
affiliations .append (a )
271
256
272
257
aff_indexes = [
273
- ", " .join (
258
+ ', ' .join (
274
259
[
275
- "%d" % (affiliations .index (a ) + 1 )
276
- for a in _aslist (author .get (" affiliation" , " Unaffiliated" ))
260
+ '%d' % (affiliations .index (a ) + 1 )
261
+ for a in _aslist (author .get (' affiliation' , ' Unaffiliated' ))
277
262
]
278
263
)
279
264
for author in hits
280
265
]
281
266
282
267
if misses :
283
268
print (
284
- "Some people made commits, but are missing in .maint/ "
285
- f"files: { ', ' .join (misses )} " ,
269
+ "Some people made commits, but are missing in .maint/ " f"files: { ', ' .join (misses )} " ,
286
270
file = sys .stderr ,
287
271
)
288
272
289
- print (" Authors (%d):" % len (hits ))
273
+ print (' Authors (%d):' % len (hits ))
290
274
print (
291
- "%s."
292
- % "; " .join (
293
- [
294
- "%s \\ :sup:`%s`\\ " % (i ["name" ], idx )
295
- for i , idx in zip (hits , aff_indexes )
296
- ]
297
- )
275
+ '%s.'
276
+ % '; ' .join (['%s \\ :sup:`%s`\\ ' % (i ['name' ], idx ) for i , idx in zip (hits , aff_indexes , strict = False )])
298
277
)
299
278
300
279
print (
301
- "\n \n Affiliations:\n %s"
302
- % "\n " .join (
303
- ["{0: >2}. {1}" .format (i + 1 , a ) for i , a in enumerate (affiliations )]
304
- )
280
+ '\n \n Affiliations:\n %s'
281
+ % '\n ' .join ([f'{ i + 1 : >2} . { a } ' for i , a in enumerate (affiliations )])
305
282
)
306
283
307
284
308
- if __name__ == " __main__" :
285
+ if __name__ == ' __main__' :
309
286
""" Install entry-point """
310
287
cli ()
0 commit comments