88# ]
99# ///
1010"""Update and sort the creators list of the zenodo record."""
11+
12+ import json
1113import sys
1214from pathlib import Path
13- import json
15+
1416import click
1517from fuzzywuzzy import fuzz , process
1618
@@ -43,21 +45,18 @@ def read_md_table(md_text):
4345 keys = None
4446 retval = []
4547 for line in md_text .splitlines ():
46- if line .strip ().startswith ("| --- |" ):
47- keys = (
48- k .replace ("*" , "" ).strip ()
49- for k in prev .split ("|" )
50- )
48+ if line .strip ().startswith ('| --- |' ):
49+ keys = (k .replace ('*' , '' ).strip () for k in prev .split ('|' ))
5150 keys = [k .lower () for k in keys if k ]
5251 continue
5352 elif not keys :
5453 prev = line
5554 continue
5655
57- if not line or not line .strip ().startswith ("|" ):
56+ if not line or not line .strip ().startswith ('|' ):
5857 break
5958
60- values = [v .strip () or None for v in line .split ("|" )][1 :- 1 ]
59+ values = [v .strip () or None for v in line .split ('|' )][1 :- 1 ]
6160 retval .append ({k : v for k , v in zip (keys , values ) if v })
6261
6362 return retval
@@ -66,21 +65,15 @@ def read_md_table(md_text):
6665def sort_contributors (entries , git_lines , exclude = None , last = None ):
6766 """Return a list of author dictionaries, ordered by contribution."""
6867 last = last or []
69- sorted_authors = sorted (entries , key = lambda i : i [" name" ])
68+ sorted_authors = sorted (entries , key = lambda i : i [' name' ])
7069
71- first_last = [
72- " " .join (val ["name" ].split ("," )[::- 1 ]).strip () for val in sorted_authors
73- ]
74- first_last_excl = [
75- " " .join (val ["name" ].split ("," )[::- 1 ]).strip () for val in exclude or []
76- ]
70+ first_last = [' ' .join (val ['name' ].split (',' )[::- 1 ]).strip () for val in sorted_authors ]
71+ first_last_excl = [' ' .join (val ['name' ].split (',' )[::- 1 ]).strip () for val in exclude or []]
7772
7873 unmatched = []
7974 author_matches = []
8075 for ele in git_lines :
81- matches = process .extract (
82- ele , first_last , scorer = fuzz .token_sort_ratio , limit = 2
83- )
76+ matches = process .extract (ele , first_last , scorer = fuzz .token_sort_ratio , limit = 2 )
8477 # matches is a list [('First match', % Match), ('Second match', % Match)]
8578 if matches [0 ][1 ] > 80 :
8679 val = sorted_authors [first_last .index (matches [0 ][0 ])]
@@ -93,15 +86,15 @@ def sort_contributors(entries, git_lines, exclude=None, last=None):
9386 if val not in author_matches :
9487 author_matches .append (val )
9588
96- names = {" " .join (val [" name" ].split ("," )[::- 1 ]).strip () for val in author_matches }
89+ names = {' ' .join (val [' name' ].split (',' )[::- 1 ]).strip () for val in author_matches }
9790 for missing_name in first_last :
9891 if missing_name not in names :
9992 missing = sorted_authors [first_last .index (missing_name )]
10093 author_matches .append (missing )
10194
10295 position_matches = []
10396 for i , item in enumerate (author_matches ):
104- pos = item .pop (" position" , None )
97+ pos = item .pop (' position' , None )
10598 if pos is not None :
10699 position_matches .append ((i , int (pos )))
107100
@@ -113,7 +106,7 @@ def sort_contributors(entries, git_lines, exclude=None, last=None):
113106 return author_matches , unmatched
114107
115108
116- def get_git_lines (fname = " line-contributors.txt" ):
109+ def get_git_lines (fname = ' line-contributors.txt' ):
117110 """Run git-line-summary."""
118111 import shutil
119112 import subprocess as sp
@@ -122,17 +115,17 @@ def get_git_lines(fname="line-contributors.txt"):
122115
123116 lines = []
124117 if contrib_file .exists ():
125- print (" WARNING: Reusing existing line-contributors.txt file." , file = sys .stderr )
118+ print (' WARNING: Reusing existing line-contributors.txt file.' , file = sys .stderr )
126119 lines = contrib_file .read_text ().splitlines ()
127120
128- cmd = [shutil .which (" git-line-summary" )]
121+ cmd = [shutil .which (' git-line-summary' )]
129122 if cmd == [None ]:
130- cmd = [shutil .which (" git-summary" ), " --line" ]
123+ cmd = [shutil .which (' git-summary' ), ' --line' ]
131124 if not lines and cmd [0 ]:
132- print (f" Running { ' ' .join (cmd )!r} on repo" )
125+ print (f' Running { " " .join (cmd )!r} on repo' )
133126 lines = sp .check_output (cmd ).decode ().splitlines ()
134- lines = [l for l in lines if " Not Committed Yet" not in l ]
135- contrib_file .write_text (" \n " .join (lines ))
127+ lines = [line for line in lines if ' Not Committed Yet' not in line ]
128+ contrib_file .write_text (' \n ' .join (lines ))
136129
137130 if not lines :
138131 raise RuntimeError (
@@ -142,15 +135,15 @@ def get_git_lines(fname="line-contributors.txt"):
142135 git-line-summary not found, please install git-extras. """
143136 * (cmd [0 ] is None )
144137 )
145- return [" " .join (line .strip ().split ()[1 :- 1 ]) for line in lines if "%" in line ]
138+ return [' ' .join (line .strip ().split ()[1 :- 1 ]) for line in lines if '%' in line ]
146139
147140
148141def _namelast (inlist ):
149142 retval = []
150143 for i in inlist :
151- i [" name" ] = (f" { i .pop (' name' , '' )} { i .pop (' lastname' , '' ) } " ).strip ()
152- if not i [" name" ]:
153- i [" name" ] = i .get (" handle" , " <Unknown Name>" )
144+ i [' name' ] = (f' { i .pop (" name" , "" )} { i .pop (" lastname" , "" ) } ' ).strip ()
145+ if not i [' name' ]:
146+ i [' name' ] = i .get (' handle' , ' <Unknown Name>' )
154147 retval .append (i )
155148 return retval
156149
@@ -162,12 +155,13 @@ def cli():
162155
163156
164157@cli .command ()
165- @click .option ("-z" , "--zenodo-file" , type = click .Path (exists = True ), default = ".zenodo.json" )
166- @click .option ("-m" , "--maintainers" , type = click .Path (exists = True ), default = ".maint/MAINTAINERS.md" )
167- @click .option ("-c" , "--contributors" , type = click .Path (exists = True ),
168- default = ".maint/CONTRIBUTORS.md" )
169- @click .option ("--pi" , type = click .Path (exists = True ), default = ".maint/PIs.md" )
170- @click .option ("-f" , "--former-file" , type = click .Path (exists = True ), default = ".maint/FORMER.md" )
158+ @click .option ('-z' , '--zenodo-file' , type = click .Path (exists = True ), default = '.zenodo.json' )
159+ @click .option ('-m' , '--maintainers' , type = click .Path (exists = True ), default = '.maint/MAINTAINERS.md' )
160+ @click .option (
161+ '-c' , '--contributors' , type = click .Path (exists = True ), default = '.maint/CONTRIBUTORS.md'
162+ )
163+ @click .option ('--pi' , type = click .Path (exists = True ), default = '.maint/PIs.md' )
164+ @click .option ('-f' , '--former-file' , type = click .Path (exists = True ), default = '.maint/FORMER.md' )
171165def zenodo (
172166 zenodo_file ,
173167 maintainers ,
@@ -188,75 +182,62 @@ def zenodo(
188182 )
189183
190184 zen_contributors , miss_contributors = sort_contributors (
191- _namelast (read_md_table (Path (contributors ).read_text ())),
192- data ,
193- exclude = former
185+ _namelast (read_md_table (Path (contributors ).read_text ())), data , exclude = former
194186 )
195187
196188 zen_pi = _namelast (reversed (read_md_table (Path (pi ).read_text ())))
197189
198- zenodo ["creators" ] = zen_creators
199- zenodo ["contributors" ] = zen_contributors + [
200- pi for pi in zen_pi if pi not in zen_contributors
201- ]
202- creator_names = {
203- c ["name" ] for c in zenodo ["creators" ]
204- if c ["name" ] != "<Unknown Name>"
205- }
206-
207- zenodo ["contributors" ] = [
208- c for c in zenodo ["contributors" ]
209- if c ["name" ] not in creator_names
210- ]
190+ zenodo ['creators' ] = zen_creators
191+ zenodo ['contributors' ] = zen_contributors + [pi for pi in zen_pi if pi not in zen_contributors ]
192+ creator_names = {c ['name' ] for c in zenodo ['creators' ] if c ['name' ] != '<Unknown Name>' }
193+
194+ zenodo ['contributors' ] = [c for c in zenodo ['contributors' ] if c ['name' ] not in creator_names ]
211195
212196 misses = set (miss_creators ).intersection (miss_contributors )
213197 if misses :
214198 print (
215- "Some people made commits, but are missing in .maint/ "
216- f"files: { ', ' .join (misses )} " ,
199+ f'Some people made commits, but are missing in .maint/ files: { ", " .join (misses )} ' ,
217200 file = sys .stderr ,
218201 )
219202
220203 # Remove position
221- for creator in zenodo ["creators" ]:
222- creator .pop ("position" , None )
223- creator .pop ("handle" , None )
224- if "affiliation" not in creator :
225- creator ["affiliation" ] = "Unknown affiliation"
226- elif isinstance (creator ["affiliation" ], list ):
227- creator ["affiliation" ] = creator ["affiliation" ][0 ]
228-
229- for creator in zenodo ["contributors" ]:
230- creator .pop ("handle" , None )
231- creator ["type" ] = "Researcher"
232- creator .pop ("position" , None )
233-
234- if "affiliation" not in creator :
235- creator ["affiliation" ] = "Unknown affiliation"
236- elif isinstance (creator ["affiliation" ], list ):
237- creator ["affiliation" ] = creator ["affiliation" ][0 ]
238-
239- Path (zenodo_file ).write_text (
240- "%s\n " % json .dumps (zenodo , indent = 2 , ensure_ascii = False )
241- )
204+ for creator in zenodo ['creators' ]:
205+ creator .pop ('position' , None )
206+ creator .pop ('handle' , None )
207+ if 'affiliation' not in creator :
208+ creator ['affiliation' ] = 'Unknown affiliation'
209+ elif isinstance (creator ['affiliation' ], list ):
210+ creator ['affiliation' ] = creator ['affiliation' ][0 ]
211+
212+ for creator in zenodo ['contributors' ]:
213+ creator .pop ('handle' , None )
214+ creator ['type' ] = 'Researcher'
215+ creator .pop ('position' , None )
216+
217+ if 'affiliation' not in creator :
218+ creator ['affiliation' ] = 'Unknown affiliation'
219+ elif isinstance (creator ['affiliation' ], list ):
220+ creator ['affiliation' ] = creator ['affiliation' ][0 ]
221+
222+ Path (zenodo_file ).write_text ('%s\n ' % json .dumps (zenodo , indent = 2 , ensure_ascii = False ))
242223
243224
244225@cli .command ()
245- @click .option ("-m" , "--maintainers" , type = click .Path (exists = True ), default = ".maint/MAINTAINERS.md" )
246- @click .option ("-c" , "--contributors" , type = click .Path (exists = True ),
247- default = ".maint/CONTRIBUTORS.md" )
248- @click .option ("--pi" , type = click .Path (exists = True ), default = ".maint/PIs.md" )
249- @click .option ("-f" , "--former-file" , type = click .Path (exists = True ), default = ".maint/FORMER.md" )
226+ @click .option ('-m' , '--maintainers' , type = click .Path (exists = True ), default = '.maint/MAINTAINERS.md' )
227+ @click .option (
228+ '-c' , '--contributors' , type = click .Path (exists = True ), default = '.maint/CONTRIBUTORS.md'
229+ )
230+ @click .option ('--pi' , type = click .Path (exists = True ), default = '.maint/PIs.md' )
231+ @click .option ('-f' , '--former-file' , type = click .Path (exists = True ), default = '.maint/FORMER.md' )
250232def publication (
251233 maintainers ,
252234 contributors ,
253235 pi ,
254236 former_file ,
255237):
256238 """Generate the list of authors and affiliations for papers."""
257- members = (
258- _namelast (read_md_table (Path (maintainers ).read_text ()))
259- + _namelast (read_md_table (Path (contributors ).read_text ()))
239+ members = _namelast (read_md_table (Path (maintainers ).read_text ())) + _namelast (
240+ read_md_table (Path (contributors ).read_text ())
260241 )
261242 former_names = _namelast (read_md_table (Path (former_file ).read_text ()))
262243
@@ -267,11 +248,8 @@ def publication(
267248 )
268249
269250 pi_hits = _namelast (reversed (read_md_table (Path (pi ).read_text ())))
270- pi_names = [pi ["name" ] for pi in pi_hits ]
271- hits = [
272- hit for hit in hits
273- if hit ["name" ] not in pi_names
274- ] + pi_hits
251+ pi_names = [pi ['name' ] for pi in pi_hits ]
252+ hits = [hit for hit in hits if hit ['name' ] not in pi_names ] + pi_hits
275253
276254 def _aslist (value ):
277255 if isinstance (value , (list , tuple )):
@@ -281,47 +259,39 @@ def _aslist(value):
281259 # Remove position
282260 affiliations = []
283261 for item in hits :
284- item .pop (" position" , None )
285- for a in _aslist (item .get (" affiliation" , " Unaffiliated" )):
262+ item .pop (' position' , None )
263+ for a in _aslist (item .get (' affiliation' , ' Unaffiliated' )):
286264 if a not in affiliations :
287265 affiliations .append (a )
288266
289267 aff_indexes = [
290- ", " .join (
268+ ', ' .join (
291269 [
292- "%d" % (affiliations .index (a ) + 1 )
293- for a in _aslist (author .get (" affiliation" , " Unaffiliated" ))
270+ '%d' % (affiliations .index (a ) + 1 )
271+ for a in _aslist (author .get (' affiliation' , ' Unaffiliated' ))
294272 ]
295273 )
296274 for author in hits
297275 ]
298276
299277 if misses :
300278 print (
301- "Some people made commits, but are missing in .maint/ "
302- f"files: { ', ' .join (misses )} " ,
279+ f'Some people made commits, but are missing in .maint/ files: { ", " .join (misses )} ' ,
303280 file = sys .stderr ,
304281 )
305282
306- print (" Authors (%d):" % len (hits ))
283+ print (' Authors (%d):' % len (hits ))
307284 print (
308- "%s."
309- % "; " .join (
310- [
311- "%s \\ :sup:`%s`\\ " % (i ["name" ], idx )
312- for i , idx in zip (hits , aff_indexes )
313- ]
314- )
285+ '%s.'
286+ % '; ' .join (['%s \\ :sup:`%s`\\ ' % (i ['name' ], idx ) for i , idx in zip (hits , aff_indexes )])
315287 )
316288
317289 print (
318- "\n \n Affiliations:\n %s"
319- % "\n " .join (
320- ["{0: >2}. {1}" .format (i + 1 , a ) for i , a in enumerate (affiliations )]
321- )
290+ '\n \n Affiliations:\n %s'
291+ % '\n ' .join (['{0: >2}. {1}' .format (i + 1 , a ) for i , a in enumerate (affiliations )])
322292 )
323293
324294
325- if __name__ == " __main__" :
295+ if __name__ == ' __main__' :
326296 """ Install entry-point """
327297 cli ()
0 commit comments