filltex 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fillbib.py +465 -0
- filltex-1.7.0.data/scripts/fillbib +465 -0
- filltex-1.7.0.data/scripts/filltex +73 -0
- filltex-1.7.0.dist-info/METADATA +18 -0
- filltex-1.7.0.dist-info/RECORD +8 -0
- filltex-1.7.0.dist-info/WHEEL +5 -0
- filltex-1.7.0.dist-info/licenses/LICENSE +21 -0
- filltex-1.7.0.dist-info/top_level.txt +1 -0
fillbib.py
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
'''
|
|
4
|
+
Query the ADS and INSPIRE databases to collect the citations used in a LaTeX file into a BibTeX file
|
|
5
|
+
|
|
6
|
+
Idea and main implementation is taken by Michele Vallisneri, see http://www.vallis.org/salon/summary-2.html
|
|
7
|
+
I changed the script to avoid the requests module, and added the INSPIRE database part.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python fillbib.py <tex_file> <bib_file>. If <bib_file> is absent, it will try to guess it from the aux file"
|
|
11
|
+
|
|
12
|
+
'''
|
|
13
|
+
from __future__ import absolute_import, print_function
|
|
14
|
+
import argparse
|
|
15
|
+
import sys, os, re, html
|
|
16
|
+
import json
|
|
17
|
+
|
|
18
|
+
if sys.version_info.major>=3:
|
|
19
|
+
import urllib.request as urllib
|
|
20
|
+
else:
|
|
21
|
+
import urllib
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def ads_citation(c): # download single ADS citation
|
|
25
|
+
#f= urllib.urlopen("http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode="+c+"&data_type=BIBTEX&db_key=AST&nocookieset=1")
|
|
26
|
+
#print("http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode="+c+"&data_type=BIBTEX&db_key=AST&nocookieset=1")
|
|
27
|
+
f= urllib.urlopen("https://ui.adsabs.harvard.edu/abs/"+c+"/exportcitation")
|
|
28
|
+
|
|
29
|
+
bib = f.read()
|
|
30
|
+
f.close()
|
|
31
|
+
if sys.version_info.major>=3:
|
|
32
|
+
bib=bib.decode()
|
|
33
|
+
bib = "@"+list(filter(lambda x:'adsnote' in x, bib.split("@")))[0].split("</textarea>")[0]
|
|
34
|
+
bib=html.unescape(bib)
|
|
35
|
+
|
|
36
|
+
return bib
|
|
37
|
+
|
|
38
|
+
def inspire_citation(key,
|
|
39
|
+
generate=False,
|
|
40
|
+
max_num_authors=None,
|
|
41
|
+
num_authors_short=None,
|
|
42
|
+
journal_arXiv_fallback=False):
|
|
43
|
+
"""
|
|
44
|
+
Generate a custom BiBTeX entry
|
|
45
|
+
|
|
46
|
+
* generate
|
|
47
|
+
if True we generate the BibTeX rather than using the default from iNSPIRE
|
|
48
|
+
* max_num_authors
|
|
49
|
+
maximum number of authors to include (all of them if None)
|
|
50
|
+
* num_authors_short
|
|
51
|
+
number of authors to include if the number of authors is longer than max_num_authors
|
|
52
|
+
if not specified, this defaults to max_num_authors
|
|
53
|
+
* journal_arXiv_fallback
|
|
54
|
+
use arXiv:eprint as the journal field if no journal is found
|
|
55
|
+
"""
|
|
56
|
+
request = 'https://inspirehep.net/api/literature?q=' + key
|
|
57
|
+
data = json.loads(urllib.urlopen(request).read())
|
|
58
|
+
if data['hits']['total'] != 1:
|
|
59
|
+
return None
|
|
60
|
+
if not generate:
|
|
61
|
+
bib = urllib.urlopen(data['hits']['hits'][0]['links']['bibtex']).read()
|
|
62
|
+
inspire_key = data['hits']['hits'][0]['metadata']['texkeys'][0]
|
|
63
|
+
if sys.version_info.major >= 3:
|
|
64
|
+
return bib.decode().replace(inspire_key, key)
|
|
65
|
+
else:
|
|
66
|
+
return bib.replace(inspire_key, key)
|
|
67
|
+
metadata = data['hits']['hits'][0]['metadata']
|
|
68
|
+
|
|
69
|
+
doctype = metadata["document_type"][0]
|
|
70
|
+
|
|
71
|
+
# BibTeX entry as a dictionary
|
|
72
|
+
bibtex = {}
|
|
73
|
+
|
|
74
|
+
# Find all authors
|
|
75
|
+
if "authors" in metadata:
|
|
76
|
+
num_authors = len(metadata["authors"])
|
|
77
|
+
if max_num_authors is not None and num_authors > max_num_authors:
|
|
78
|
+
short_author_list = True
|
|
79
|
+
if num_authors_short is None:
|
|
80
|
+
num_authors_short = max_num_authors
|
|
81
|
+
else:
|
|
82
|
+
short_author_list = False
|
|
83
|
+
author_list = []
|
|
84
|
+
for idx, author in enumerate(metadata['authors']):
|
|
85
|
+
if short_author_list and idx >= num_authors_short:
|
|
86
|
+
author_list.append("others")
|
|
87
|
+
break
|
|
88
|
+
author_list.append(author['full_name'])
|
|
89
|
+
bibtex['author'] = " and ".join(author_list)
|
|
90
|
+
|
|
91
|
+
# Find all collaborations
|
|
92
|
+
if "collaborations" in metadata:
|
|
93
|
+
collab_list = []
|
|
94
|
+
for collab in metadata["collaborations"]:
|
|
95
|
+
collab_list.append(collab["value"])
|
|
96
|
+
bibtex["collaboration"] = ", ".join(collab_list)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
bibtex["title"] = "{" + metadata["titles"][0]["title"] + "}"
|
|
100
|
+
except KeyError:
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
bibtex["eprint"] = metadata["arxiv_eprints"][0]["value"]
|
|
105
|
+
bibtex["archivePrefix"] = "arXiv"
|
|
106
|
+
bibtex["primaryClass"] = metadata["arxiv_eprints"][0]["categories"][0]
|
|
107
|
+
except KeyError:
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
bibtex["doi"] = metadata["dois"][0]["value"]
|
|
112
|
+
except KeyError:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
bibtex["journal"] = metadata["publication_info"][0]["journal_title"]
|
|
117
|
+
except KeyError:
|
|
118
|
+
if journal_arXiv_fallback:
|
|
119
|
+
bibtex["journal"] = "arXiv:" + bibtex["eprint"]
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
bibtex["volume"] = metadata["publication_info"][0]["journal_volume"]
|
|
124
|
+
except KeyError:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
bibtex["number"] = metadata["publication_info"][0]["journal_issue"]
|
|
129
|
+
except KeyError:
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
bibtex["pages"] = metadata["publication_info"][0]["page_start"]
|
|
134
|
+
except KeyError:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
bibtex["year"] = metadata["publication_info"][0]["year"]
|
|
139
|
+
except KeyError:
|
|
140
|
+
try:
|
|
141
|
+
bibtex["year"] = metadata["preprint_date"][0:4]
|
|
142
|
+
bibtex["month"] = str(int(metadata["preprint_date"][5:7]))
|
|
143
|
+
except KeyError:
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
# Format BibTeX entry
|
|
147
|
+
s = "@{}{{{}".format(doctype, key)
|
|
148
|
+
for field, value in bibtex.items():
|
|
149
|
+
s += ",\n {} = \"{}\"".format(field, value)
|
|
150
|
+
s += "\n}"
|
|
151
|
+
|
|
152
|
+
return s
|
|
153
|
+
|
|
154
|
+
def test_ads(): # test single ADS web scraping (both published articles and preprints)
|
|
155
|
+
test_key = ["2016PhRvL.116f1102A","2016arXiv160203837T"]
|
|
156
|
+
known_output= '@ARTICLE{2016PhRvL.116f1102A,\n author = {{Abbott}, B.~P. and {Abbott}, R. and {Abbott}, T.~D. and {Abernathy}, M.~R. and \n\t{Acernese}, F. and {Ackley}, K. and {Adams}, C. and {Adams}, T. and \n\t{Addesso}, P. and {Adhikari}, R.~X. and et al.},\n title = "{Observation of Gravitational Waves from a Binary Black Hole Merger}",\n journal = {Physical Review Letters},\narchivePrefix = "arXiv",\n eprint = {1602.03837},\n primaryClass = "gr-qc",\n year = 2016,\n month = feb,\n volume = 116,\n number = 6,\n eid = {061102},\n pages = {061102},\n doi = {10.1103/PhysRevLett.116.061102},\n adsurl = {http://adsabs.harvard.edu/abs/2016PhRvL.116f1102A},\n adsnote = {Provided by the SAO/NASA Astrophysics Data System}\n}\n\n'
|
|
157
|
+
assert [ads_citation(tk) == known_output for tk in test_key]
|
|
158
|
+
|
|
159
|
+
def test_inspire(): # test single INSPIRE web scraping
|
|
160
|
+
test_key = "Abbott:2016blz"
|
|
161
|
+
known_output = '@article{Abbott:2016blz,\n author = "Abbott, B.P. and Abbott, R. and Abbott, T.D. and Abernathy, M.R. and Acernese, F. and others",\n collaboration = "LIGO Scientific, Virgo",\n title = "{Observation of Gravitational Waves from a Binary Black Hole Merger}",\n eprint = "1602.03837",\n archivePrefix = "arXiv",\n primaryClass = "gr-qc",\n doi = "10.1103/PhysRevLett.116.061102",\n journal = "Phys.Rev.Lett.",\n volume = "116",\n number = "6",\n year = "2016"\n}'
|
|
162
|
+
assert inspire_citation(test_key, generate=True, max_num_authors=5) == known_output
|
|
163
|
+
|
|
164
|
+
def fillbib_tex(args):
|
|
165
|
+
|
|
166
|
+
if args.bibtex is None: # Get the name of the bibfile from the aux file
|
|
167
|
+
basename = args.texfile[0].split('.tex')[0]
|
|
168
|
+
auxfile = basename + '.aux'
|
|
169
|
+
for line in open(auxfile,'r'):
|
|
170
|
+
m = re.search(r'\\bibdata\{(.*)\}',line) # match \citation{...}, collect the ... note that we escape \, {, and }
|
|
171
|
+
if m:
|
|
172
|
+
bibfile = list(filter(lambda x:x!=basename+'Notes', m.group(1).split(',')))[0] # Remove that annyoing feature of revtex which creates a *Notes.bib bibfile. Note this is not solid if you want to handle multiple bib files.
|
|
173
|
+
bibfile = bibfile + '.bib'
|
|
174
|
+
|
|
175
|
+
else: # Bibfile specified from argv
|
|
176
|
+
basename = args.texfile[0].split('.tex')[0]
|
|
177
|
+
auxfile = basename + '.aux'
|
|
178
|
+
bibfile = args.bibtex.split('.bib')[0] + '.bib'
|
|
179
|
+
|
|
180
|
+
if args.updatepublished:
|
|
181
|
+
with open(basename+".tex", 'r') as texfile:
|
|
182
|
+
texdata = texfile.read()
|
|
183
|
+
|
|
184
|
+
# Get all citations from aux file. Citations will look like \citation{2004PhRvD..69j4017P,2004PhRvD..69j4017P}
|
|
185
|
+
cites = set() # use a set (no repetitions)
|
|
186
|
+
for line in open(auxfile,'r'):
|
|
187
|
+
m = re.search(r'\\citation\{(.*)\}',line) # find \citation{...}
|
|
188
|
+
if m:
|
|
189
|
+
cites.update(m.group(1).split(',')) # split by commas
|
|
190
|
+
|
|
191
|
+
cites= cites.difference([
|
|
192
|
+
'REVTEX41Control','apsrev41Control',
|
|
193
|
+
'REVTEX42Control','apsrev42Control']) # Remove annoying entries of revtex
|
|
194
|
+
|
|
195
|
+
print("Seek:", cites)
|
|
196
|
+
|
|
197
|
+
# Check what you already have in the bib file
|
|
198
|
+
haves = []
|
|
199
|
+
if os.path.isfile(bibfile):
|
|
200
|
+
for line in open(bibfile,'r'):
|
|
201
|
+
m = re.search(r'@.*?\{(.*),',line) # .*\{ means "any # of any char followed by {"; .*?\{ means "the shortest string matching any # of any char followed by {"
|
|
202
|
+
if m:
|
|
203
|
+
haves.append(m.group(1))
|
|
204
|
+
print("Have:", haves)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# Query ADS and INSPIRE
|
|
208
|
+
bibtex = open(bibfile,'a') # open for appending
|
|
209
|
+
|
|
210
|
+
for c in cites:
|
|
211
|
+
if c and c not in haves: # c is something and you don't have it already
|
|
212
|
+
|
|
213
|
+
if not c[0].isalpha(): # The first charachter is a number: could be on ADS
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
bib = ads_citation(c)
|
|
217
|
+
|
|
218
|
+
cfound = bib.split("{")[1].split(',')[0]
|
|
219
|
+
|
|
220
|
+
if cfound == c: # Check you got what you where looking for
|
|
221
|
+
pass
|
|
222
|
+
elif 'arXiv' in c: # Take care of preprint on ADS
|
|
223
|
+
|
|
224
|
+
if args.updatepublished and '.tmp.' not in cfound:
|
|
225
|
+
print("ADS replace", c, "-->", cfound)
|
|
226
|
+
# This substitute the new ID into the tex file. Use at your own risk. The .tmp. condition fixes those stupid MNRAS temp entries.
|
|
227
|
+
texdata = texdata.replace(c, cfound)
|
|
228
|
+
|
|
229
|
+
else:
|
|
230
|
+
# This subsitute the arxiv id back in to the bib file
|
|
231
|
+
bib = bib.split("{")[0]+"{"+c+","+",".join(bib.split(",")[1:])
|
|
232
|
+
|
|
233
|
+
bibtex.write(bib)
|
|
234
|
+
print("ADS Found:", c)
|
|
235
|
+
except:
|
|
236
|
+
print("ADS Not found:", c)
|
|
237
|
+
|
|
238
|
+
else: # The first charachter is not a number: could be on INSPIRE
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
bib = inspire_citation(c,
|
|
242
|
+
generate=args.generate,
|
|
243
|
+
max_num_authors=args.max_num_authors,
|
|
244
|
+
num_authors_short=args.num_authors_short,
|
|
245
|
+
journal_arXiv_fallback=args.journal_arXiv_fallback)
|
|
246
|
+
bibtex.write(bib)
|
|
247
|
+
print("INSPIRE Found:", c)
|
|
248
|
+
except:
|
|
249
|
+
print("INSPIRE Not found:", c)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
bibtex.close()
|
|
254
|
+
|
|
255
|
+
if args.updatepublished:
|
|
256
|
+
with open(basename+".tex", 'w') as texfile:
|
|
257
|
+
texfile.write(texdata)
|
|
258
|
+
|
|
259
|
+
# Clean up journal names
|
|
260
|
+
if args.journals:
|
|
261
|
+
journals(bibfile)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def fillbib_list(args):
|
|
265
|
+
for c in args.keys:
|
|
266
|
+
if not c[0].isalpha():
|
|
267
|
+
bib = ads_citation(c)
|
|
268
|
+
if bib is None:
|
|
269
|
+
sys.stderr.write("ADS Not Found: {}\n".format(c))
|
|
270
|
+
else:
|
|
271
|
+
print(bib)
|
|
272
|
+
else:
|
|
273
|
+
bib = inspire_citation(c,
|
|
274
|
+
generate=args.generate,
|
|
275
|
+
max_num_authors=args.max_num_authors,
|
|
276
|
+
num_authors_short=args.num_authors_short,
|
|
277
|
+
journal_arXiv_fallback=args.journal_arXiv_fallback)
|
|
278
|
+
if bib is None:
|
|
279
|
+
sys.stderr.write("INSPIRE Not Found: {}\n".format(c))
|
|
280
|
+
else:
|
|
281
|
+
print(bib)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def curly(x):
|
|
285
|
+
'''Just a curly bracket sandwich.'''
|
|
286
|
+
return "{"+x+"}"
|
|
287
|
+
|
|
288
|
+
def journals(bibfile):
|
|
289
|
+
'''
|
|
290
|
+
Clean up the names of some journals using their ISO4 standards.
|
|
291
|
+
Journal abbreviations are taken from https://images.webofknowledge.com/images/help/WOS/A_abrvjt.html
|
|
292
|
+
If your favourite journal is missing, please add it and send a pull request. Thanks!
|
|
293
|
+
'''
|
|
294
|
+
|
|
295
|
+
# The format is: [ADS name, INSPIRE name, ISO4 abbreviation]
|
|
296
|
+
journals = [
|
|
297
|
+
####
|
|
298
|
+
# These are the journals from the ADS macros: https://ui.adsabs.harvard.edu/help/actions/journal-macros
|
|
299
|
+
# I could not find them all on INSPIRE, some are missing.
|
|
300
|
+
####
|
|
301
|
+
['\\aj', 'Astron. J.', 'Astron. J.'],
|
|
302
|
+
['\\actaa', 'Acta Astron.', 'Acta Astronom.'],
|
|
303
|
+
['\\araa', 'Ann. Rev. Astron. Astrophys.', 'Annu. Rev. Astron. Astrophys.'],
|
|
304
|
+
['\\apj', 'Astrophys. J.', 'Astrophys. J.'],
|
|
305
|
+
['\\apjl', 'Astrophys. J. Lett.', 'Astrophys. J. Lett.'],
|
|
306
|
+
['\\apjs', 'Astrophys. J. Suppl.', 'Astrophys. J. Supp. S.'],
|
|
307
|
+
['\\ao', 'Appl. Opt.', 'Appl. Optics'],
|
|
308
|
+
['\\apss', 'Astrophys. Space Sci.', 'Astrophys. Space Sci.'],
|
|
309
|
+
['\\aap', 'Astron. Astrophys.', 'Astron. Astrophys.'],
|
|
310
|
+
['\\aapr', 'Astron. Astrophys. Rev.', 'Astron. Astrophys. Rev.'],
|
|
311
|
+
['\\aaps', 'Astron. Astrophys. Suppl. Ser.', 'Astron. Astrophys. Sup.'],
|
|
312
|
+
['\\azh', '', 'Astron. Zh.'], #Not sure. Various names on inspire
|
|
313
|
+
['\\baas', 'Bull. Am. Astron. Soc.', 'Bull. Am. Astron. Soc.'],
|
|
314
|
+
['\\bac', 'Bull. Astron. Inst. Czech.', 'B. Astron. I. Czech.'],
|
|
315
|
+
['\\caa', 'Chin. Astron. Astrophys.', 'Chinese Astron. Astr.'],
|
|
316
|
+
['\\cjaa', 'Chin. J. Astron. Astrophys.', 'Chinese J. Astron. Ast.'],
|
|
317
|
+
['\\icarus', 'Icarus', 'Icarus'],
|
|
318
|
+
['\\jcap', 'JCAP', 'J. Cosmology Astropart. Phys.'],
|
|
319
|
+
['\\jrasc', 'J. Roy. Astron. Soc. Canada', 'J. Roy Astron. Soc. Can.'],
|
|
320
|
+
['\\memras', 'Mem. Roy. Astron. Soc.', 'Mem. R. Astron. Soc.'],
|
|
321
|
+
['\\mnras', 'Mon. Not. Roy. Astron. Soc.', 'Mon. Not. R. Astron. Soc.'],
|
|
322
|
+
['\\na', 'New Astron.', 'New Astron.'],
|
|
323
|
+
['\\nar', 'New Astron. Rev.', 'New Astron. Rev.'],
|
|
324
|
+
['\\pra', 'Phys. Rev. A', 'Phys. Rev. A'],
|
|
325
|
+
['\\prb', 'Phys. Rev. B', 'Phys. Rev. B'],
|
|
326
|
+
['\\prc', 'Phys. Rev. C', 'Phys. Rev. C'],
|
|
327
|
+
['\\prd', 'Phys. Rev. D', 'Phys. Rev. D'],
|
|
328
|
+
['\\pre', 'Phys. Rev. E', 'Phys. Rev. E'],
|
|
329
|
+
['\\prl', 'Phys. Rev. Lett.', 'Phys. Rev. Lett.'],
|
|
330
|
+
['\\pasa', 'Publ. Astron. Soc. Austral.', 'Publ. Astron. Soc. Aust.'],
|
|
331
|
+
['\\pasp', 'Publ. Astron. Soc. Pac.', 'Publ. Astron. Soc. Pac.'],
|
|
332
|
+
['\\pasj', 'Publ. Astron. Soc. Jap.', 'Publ. Astron. Soc. Jpn.'],
|
|
333
|
+
['\\rmxaa', 'Rev. Mex. Astron. Astrofis.', 'Rev. Mex. Astron. Astr.'],
|
|
334
|
+
['\\qjras', 'Q. J. Roy. Astron. Soc.', 'Q. J. Roy. Astron. Soc.'],
|
|
335
|
+
['\\skytel', 'Sky Telesc.', 'Sky Telescope'],
|
|
336
|
+
['\\solphys', 'Solar Phys.', 'Sol. Phys.'],
|
|
337
|
+
['\\sovast', 'Sov. Astron.', 'Sov. Astron.'],
|
|
338
|
+
['\\ssr', 'Space Sci. Rev.', 'Space Sci. Rev.'],
|
|
339
|
+
['\\zap', 'Z. Astrophys.', 'Z. Astrophys.'],
|
|
340
|
+
['\\nat', 'Nature', 'Nature'],
|
|
341
|
+
['\\iaucirc', 'IAU Circ.', 'IAU Circ.'],
|
|
342
|
+
['\\aplett', 'Astrophys. Lett.', 'Astrophys. Lett.'],
|
|
343
|
+
['\\apspr', '', 'Astrophys.~Space~Phys.~Res.'], #Could not find it on INSPIRE
|
|
344
|
+
['\\bain', 'Bull. Astron. Inst. Netherlands', 'B. Astron. I. Neth.'],
|
|
345
|
+
['\\fcp', 'Fund. Cosmic Phys.', 'Fund. Cosmic Phys.'],
|
|
346
|
+
['\\gca', 'Geochim. Cosmochim. Acta', 'Geochim. Cosmochim. Ac.'],
|
|
347
|
+
['\\grl', 'Geophys. Res. Lett.', 'Geophys. Res. Lett.'],
|
|
348
|
+
['\\jcp', 'J. Chem. Phys.', 'J. Chem. Phys.'],
|
|
349
|
+
['\\jgr', 'J. Geophys. Res.', 'J. Geophys. Res.'],
|
|
350
|
+
['\\jqsrt', 'J. Quant. Spectrosc. Radiat. Trans.', 'J. Quant. Sprectrosc. Ra.'],
|
|
351
|
+
['\\memsai', 'Mem. Soc. Ast. It.', 'Mem. Soc. Astron. Ital.'],
|
|
352
|
+
['\\nphysa', 'Nucl. Phys. A', 'Nucl. Phys. A'],
|
|
353
|
+
['\\physrep', 'Phys. Rept.', 'Phys. Rep.'],
|
|
354
|
+
['\\physscr', 'Phys. Scripta', 'Phys. Scripta'],
|
|
355
|
+
['\\planss', 'Planet. Space Sci.', 'Planet. Space Sci.'],
|
|
356
|
+
['\\procspie', 'Proc. SPIE Int. Soc. Opt. Eng.', 'P. Soc. Photo.-Opt. Ins.'],
|
|
357
|
+
####
|
|
358
|
+
# [Davide Gerosa] These are journals that I personally encountered.
|
|
359
|
+
# Will keep on adding to this list.
|
|
360
|
+
####
|
|
361
|
+
['Advances in Space Research','Adv. Space Res.','Adv. Space Res.'], #ISI list not correct
|
|
362
|
+
['American Institute of Physics Conference Series','AIP Conf. Proc.','AIP Conf. Proc.'],
|
|
363
|
+
['Annals of Data Science','Ann. Data Sci.','Ann. Data Sci.'],
|
|
364
|
+
['Astronomy and Computing','Astron. Comput.','Astron. Comput.'],
|
|
365
|
+
['Astroparticle Physics','Astropart. Phys.','Astropart. Phys.'],
|
|
366
|
+
['Astrophysics and Space Science Library','Astrophys. Space Sci. Libr.','Astrophys. Space Sc. L.'],
|
|
367
|
+
['Astrophysics and Space Science Library','Astrophys. Space Sci. Libr.','Astrophys. Space Sc. L.'],
|
|
368
|
+
['Bulletin of the American Astronomical Society','Bull. Am. Astron. Soc.','Bull. Am. Astron. Soc.'],
|
|
369
|
+
['Classical and Quantum Gravity','Class. Quant. Grav.','Class. Quantum Grav.'], #ISI list not correct
|
|
370
|
+
['Communications in Mathematical Physics', 'Commun. Math. Phys.', 'Commun. Math. Phys.'],
|
|
371
|
+
['Frontiers in Astronomy and Space Sciences','Front. Astron. Space Sci.','Front. Astron. Space Sci.'],
|
|
372
|
+
['General Relativity and Gravitation', 'Gen. Rel. Grav.', 'Gen. Relat. Gravit.'],
|
|
373
|
+
['International Journal of Modern Physics D', 'Int. J. Mod. Phys. D', 'Int. J. Mod. Phys. D'],
|
|
374
|
+
['iScience', 'iScience', 'iScience'],
|
|
375
|
+
['Journal of High Energy Physics','JHEP','J. High Energy Phys.'],
|
|
376
|
+
['Journal of Machine Learning Research','J. Machine Learning Res.','J. Mach. Learn. Res.'],
|
|
377
|
+
['Journal of Mathematical Analysis and Applications','J. Math. Anal. Appl.','J. Math. Anal. Appl'],
|
|
378
|
+
['Journal of Physics Conference Series','J. Phys. Conf. Ser.','J. Phys. Conf. Ser.'],
|
|
379
|
+
['Journal of Statistical Physics','J. Statist. Phys.','J. Stat. Phys.'],
|
|
380
|
+
['Journal of the Royal Statistical Society B','J. Roy. Statist. Soc. B','J. Roy. Statist. Soc. B'],
|
|
381
|
+
['Living Reviews in Relativity', 'Living Rev. Rel.', 'Living Rev. Relativ.'],
|
|
382
|
+
['Machine Learning: Science and Technology','Mach. Learn. Sci. Tech.','Mach. Learn. Sci. Tech.'], #ISI list not correct
|
|
383
|
+
['Machine Learning','Machine Learning','Mach. Learn.'],
|
|
384
|
+
['Nature Astronomy', 'Nature Astron.', 'Nat. Astron.'],
|
|
385
|
+
['Nature Methods', 'Nature Meth.', 'Nat. Methods'],
|
|
386
|
+
['Nature Reviews Physics','Nature Rev. Phys.','Nat. Rev. Phys.'],
|
|
387
|
+
['Physica A Statistical Mechanics and its Applications','Physica A','Physica A'],
|
|
388
|
+
['Physica D Nonlinear Phenomena', 'Physica D', 'Physica D'],
|
|
389
|
+
['Physical Review', 'Phys. Rev.', 'Phys. Rev.'],
|
|
390
|
+
['Physical Review Research', 'Phys. Rev. Res.', 'Phys. Rev. Res.'],
|
|
391
|
+
['Physical Review X', 'Phys. Rev. X', 'Phys. Rev. X'],
|
|
392
|
+
['Physics Letters A', 'Phys. Lett. A', 'Phys. Lett. A'],
|
|
393
|
+
['Proceedings of the Royal Society of London Series A', 'Proc. Roy. Soc. Lond. A', 'P. R. Soc. Lond. A'],
|
|
394
|
+
['Rendiconti Lincei. Scienze Fisiche e Naturali', 'Rend. Lincei Sci. Fis. Nat.', 'Rend. Lincei-Sci. Fis.'],
|
|
395
|
+
['Reports on Progress in Physics', 'Rept. Prog. Phys.', 'Rep. Prog. Phys.'],
|
|
396
|
+
['Research Notes of the American Astronomical Society', 'Res. Notes AAS','Res. Notes AAS'],
|
|
397
|
+
['Reviews of Modern Physics', 'Rev. Mod. Phys.', 'Rev. Mod. Phys.'],
|
|
398
|
+
['Science Advances','Sci. Adv.','Sci. Adv.'],
|
|
399
|
+
['SIAM Journal on Scientific Computing','SIAM J. Sci. Comput.','SIAM J. Sci. Comput.'],
|
|
400
|
+
['The Journal of Open Source Software','J. Open Source Softw.','J. Open Source Softw.'],
|
|
401
|
+
]
|
|
402
|
+
|
|
403
|
+
with open(bibfile, 'r') as bibtex :
|
|
404
|
+
filedata = bibtex.read()
|
|
405
|
+
|
|
406
|
+
for j in journals:
|
|
407
|
+
print(j)
|
|
408
|
+
if j[0]:
|
|
409
|
+
filedata = filedata.replace(curly(j[0]), curly(j[2]))
|
|
410
|
+
if j[1]:
|
|
411
|
+
filedata = filedata.replace(curly(j[1]), curly(j[2]))
|
|
412
|
+
filedata = filedata.replace('journal = "'+j[1], 'journal = "'+j[2])
|
|
413
|
+
|
|
414
|
+
### Clean up arxiv repeated information in ADS records:
|
|
415
|
+
filedata = filedata.replace('arXiv e-prints', '{}')
|
|
416
|
+
filedata = re.sub('pages = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
417
|
+
filedata = re.sub('Pages = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
418
|
+
filedata = re.sub('eid = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
419
|
+
filedata = re.sub('Eid = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
420
|
+
filedata = re.sub('doi = {[0-9]+.[0-9]+/arXiv.[0-9]+.[0-9]+},','',filedata)
|
|
421
|
+
|
|
422
|
+
with open(bibfile, 'w') as bibtex :
|
|
423
|
+
bibtex.write(filedata)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
if __name__ == "__main__":
|
|
429
|
+
|
|
430
|
+
parser = argparse.ArgumentParser()
|
|
431
|
+
parser.add_argument("--generate", action="store_true",
|
|
432
|
+
help="Generate the BibTeX entries from the metadata "
|
|
433
|
+
"(this is useful to customize the generated BiBTeX file)")
|
|
434
|
+
parser.add_argument("--journal_arXiv_fallback", dest="journal_arXiv_fallback", action="store_true",
|
|
435
|
+
help="Set the journal entry to be arXiv for unpublished preprints "
|
|
436
|
+
"(iNSPIRE entries only, requres --generate)")
|
|
437
|
+
parser.add_argument("--max-num-authors", dest="max_num_authors", type=int,
|
|
438
|
+
help="Include at most this many authors for each bibtex entry"
|
|
439
|
+
"(iNSPIRE entries only, requres --generate)")
|
|
440
|
+
parser.add_argument("--num-authors-short", type=int,
|
|
441
|
+
help="Number of authors to list if the number of authors is larger than max_num_authors"
|
|
442
|
+
"(iNSPIRE entries only, defaults to max-num-authors, requres --generate)")
|
|
443
|
+
subparsers = parser.add_subparsers(help="Subcommands")
|
|
444
|
+
|
|
445
|
+
parser_tex = subparsers.add_parser("tex", help="Create a bibliography for a tex document")
|
|
446
|
+
parser_tex.add_argument("--bibtex", help="The BiBTeX file to use (if not specified we try to find out)")
|
|
447
|
+
parser_tex.add_argument("texfile", nargs=1, help="The (La)TeX file to process")
|
|
448
|
+
parser_tex.add_argument('--journals', dest='journals', help="Replace known journal abbreviations", default=True, action='store_true')
|
|
449
|
+
parser_tex.add_argument('--updatepublished', dest='updatepublished', help="Replace ADS arxiv entries in .tex file if published", default=True, action='store_true')
|
|
450
|
+
parser_tex.set_defaults(func=fillbib_tex)
|
|
451
|
+
|
|
452
|
+
parser_list = subparsers.add_parser("list", help="Create a bibliography given a list of ADS/iNSPIRE keys")
|
|
453
|
+
parser_list.add_argument("keys", nargs="+", help="ADS/iNSPIRE keys to fetch")
|
|
454
|
+
parser_list.set_defaults(func=fillbib_list)
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
args = parser.parse_args()
|
|
458
|
+
args.func(args)
|
|
459
|
+
#try:
|
|
460
|
+
# args.func(args)
|
|
461
|
+
#except:
|
|
462
|
+
# parser.print_usage()
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
#!python
|
|
2
|
+
|
|
3
|
+
'''
|
|
4
|
+
Query the ADS and INSPIRE databases to collect the citations used in a LaTeX file into a BibTeX file
|
|
5
|
+
|
|
6
|
+
Idea and main implementation is taken by Michele Vallisneri, see http://www.vallis.org/salon/summary-2.html
|
|
7
|
+
I changed the script to avoid the requests module, and added the INSPIRE database part.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python fillbib.py <tex_file> <bib_file>. If <bib_file> is absent, it will try to guess it from the aux file"
|
|
11
|
+
|
|
12
|
+
'''
|
|
13
|
+
from __future__ import absolute_import, print_function
|
|
14
|
+
import argparse
|
|
15
|
+
import sys, os, re, html
|
|
16
|
+
import json
|
|
17
|
+
|
|
18
|
+
if sys.version_info.major>=3:
|
|
19
|
+
import urllib.request as urllib
|
|
20
|
+
else:
|
|
21
|
+
import urllib
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def ads_citation(c): # download single ADS citation
|
|
25
|
+
#f= urllib.urlopen("http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode="+c+"&data_type=BIBTEX&db_key=AST&nocookieset=1")
|
|
26
|
+
#print("http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode="+c+"&data_type=BIBTEX&db_key=AST&nocookieset=1")
|
|
27
|
+
f= urllib.urlopen("https://ui.adsabs.harvard.edu/abs/"+c+"/exportcitation")
|
|
28
|
+
|
|
29
|
+
bib = f.read()
|
|
30
|
+
f.close()
|
|
31
|
+
if sys.version_info.major>=3:
|
|
32
|
+
bib=bib.decode()
|
|
33
|
+
bib = "@"+list(filter(lambda x:'adsnote' in x, bib.split("@")))[0].split("</textarea>")[0]
|
|
34
|
+
bib=html.unescape(bib)
|
|
35
|
+
|
|
36
|
+
return bib
|
|
37
|
+
|
|
38
|
+
def inspire_citation(key,
|
|
39
|
+
generate=False,
|
|
40
|
+
max_num_authors=None,
|
|
41
|
+
num_authors_short=None,
|
|
42
|
+
journal_arXiv_fallback=False):
|
|
43
|
+
"""
|
|
44
|
+
Generate a custom BiBTeX entry
|
|
45
|
+
|
|
46
|
+
* generate
|
|
47
|
+
if True we generate the BibTeX rather than using the default from iNSPIRE
|
|
48
|
+
* max_num_authors
|
|
49
|
+
maximum number of authors to include (all of them if None)
|
|
50
|
+
* num_authors_short
|
|
51
|
+
number of authors to include if the number of authors is longer than max_num_authors
|
|
52
|
+
if not specified, this defaults to max_num_authors
|
|
53
|
+
* journal_arXiv_fallback
|
|
54
|
+
use arXiv:eprint as the journal field if no journal is found
|
|
55
|
+
"""
|
|
56
|
+
request = 'https://inspirehep.net/api/literature?q=' + key
|
|
57
|
+
data = json.loads(urllib.urlopen(request).read())
|
|
58
|
+
if data['hits']['total'] != 1:
|
|
59
|
+
return None
|
|
60
|
+
if not generate:
|
|
61
|
+
bib = urllib.urlopen(data['hits']['hits'][0]['links']['bibtex']).read()
|
|
62
|
+
inspire_key = data['hits']['hits'][0]['metadata']['texkeys'][0]
|
|
63
|
+
if sys.version_info.major >= 3:
|
|
64
|
+
return bib.decode().replace(inspire_key, key)
|
|
65
|
+
else:
|
|
66
|
+
return bib.replace(inspire_key, key)
|
|
67
|
+
metadata = data['hits']['hits'][0]['metadata']
|
|
68
|
+
|
|
69
|
+
doctype = metadata["document_type"][0]
|
|
70
|
+
|
|
71
|
+
# BibTeX entry as a dictionary
|
|
72
|
+
bibtex = {}
|
|
73
|
+
|
|
74
|
+
# Find all authors
|
|
75
|
+
if "authors" in metadata:
|
|
76
|
+
num_authors = len(metadata["authors"])
|
|
77
|
+
if max_num_authors is not None and num_authors > max_num_authors:
|
|
78
|
+
short_author_list = True
|
|
79
|
+
if num_authors_short is None:
|
|
80
|
+
num_authors_short = max_num_authors
|
|
81
|
+
else:
|
|
82
|
+
short_author_list = False
|
|
83
|
+
author_list = []
|
|
84
|
+
for idx, author in enumerate(metadata['authors']):
|
|
85
|
+
if short_author_list and idx >= num_authors_short:
|
|
86
|
+
author_list.append("others")
|
|
87
|
+
break
|
|
88
|
+
author_list.append(author['full_name'])
|
|
89
|
+
bibtex['author'] = " and ".join(author_list)
|
|
90
|
+
|
|
91
|
+
# Find all collaborations
|
|
92
|
+
if "collaborations" in metadata:
|
|
93
|
+
collab_list = []
|
|
94
|
+
for collab in metadata["collaborations"]:
|
|
95
|
+
collab_list.append(collab["value"])
|
|
96
|
+
bibtex["collaboration"] = ", ".join(collab_list)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
bibtex["title"] = "{" + metadata["titles"][0]["title"] + "}"
|
|
100
|
+
except KeyError:
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
bibtex["eprint"] = metadata["arxiv_eprints"][0]["value"]
|
|
105
|
+
bibtex["archivePrefix"] = "arXiv"
|
|
106
|
+
bibtex["primaryClass"] = metadata["arxiv_eprints"][0]["categories"][0]
|
|
107
|
+
except KeyError:
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
bibtex["doi"] = metadata["dois"][0]["value"]
|
|
112
|
+
except KeyError:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
bibtex["journal"] = metadata["publication_info"][0]["journal_title"]
|
|
117
|
+
except KeyError:
|
|
118
|
+
if journal_arXiv_fallback:
|
|
119
|
+
bibtex["journal"] = "arXiv:" + bibtex["eprint"]
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
bibtex["volume"] = metadata["publication_info"][0]["journal_volume"]
|
|
124
|
+
except KeyError:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
bibtex["number"] = metadata["publication_info"][0]["journal_issue"]
|
|
129
|
+
except KeyError:
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
bibtex["pages"] = metadata["publication_info"][0]["page_start"]
|
|
134
|
+
except KeyError:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
bibtex["year"] = metadata["publication_info"][0]["year"]
|
|
139
|
+
except KeyError:
|
|
140
|
+
try:
|
|
141
|
+
bibtex["year"] = metadata["preprint_date"][0:4]
|
|
142
|
+
bibtex["month"] = str(int(metadata["preprint_date"][5:7]))
|
|
143
|
+
except KeyError:
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
# Format BibTeX entry
|
|
147
|
+
s = "@{}{{{}".format(doctype, key)
|
|
148
|
+
for field, value in bibtex.items():
|
|
149
|
+
s += ",\n {} = \"{}\"".format(field, value)
|
|
150
|
+
s += "\n}"
|
|
151
|
+
|
|
152
|
+
return s
|
|
153
|
+
|
|
154
|
+
def test_ads(): # test single ADS web scraping (both published articles and preprints)
|
|
155
|
+
test_key = ["2016PhRvL.116f1102A","2016arXiv160203837T"]
|
|
156
|
+
known_output= '@ARTICLE{2016PhRvL.116f1102A,\n author = {{Abbott}, B.~P. and {Abbott}, R. and {Abbott}, T.~D. and {Abernathy}, M.~R. and \n\t{Acernese}, F. and {Ackley}, K. and {Adams}, C. and {Adams}, T. and \n\t{Addesso}, P. and {Adhikari}, R.~X. and et al.},\n title = "{Observation of Gravitational Waves from a Binary Black Hole Merger}",\n journal = {Physical Review Letters},\narchivePrefix = "arXiv",\n eprint = {1602.03837},\n primaryClass = "gr-qc",\n year = 2016,\n month = feb,\n volume = 116,\n number = 6,\n eid = {061102},\n pages = {061102},\n doi = {10.1103/PhysRevLett.116.061102},\n adsurl = {http://adsabs.harvard.edu/abs/2016PhRvL.116f1102A},\n adsnote = {Provided by the SAO/NASA Astrophysics Data System}\n}\n\n'
|
|
157
|
+
assert [ads_citation(tk) == known_output for tk in test_key]
|
|
158
|
+
|
|
159
|
+
def test_inspire(): # test single INSPIRE web scraping
|
|
160
|
+
test_key = "Abbott:2016blz"
|
|
161
|
+
known_output = '@article{Abbott:2016blz,\n author = "Abbott, B.P. and Abbott, R. and Abbott, T.D. and Abernathy, M.R. and Acernese, F. and others",\n collaboration = "LIGO Scientific, Virgo",\n title = "{Observation of Gravitational Waves from a Binary Black Hole Merger}",\n eprint = "1602.03837",\n archivePrefix = "arXiv",\n primaryClass = "gr-qc",\n doi = "10.1103/PhysRevLett.116.061102",\n journal = "Phys.Rev.Lett.",\n volume = "116",\n number = "6",\n year = "2016"\n}'
|
|
162
|
+
assert inspire_citation(test_key, generate=True, max_num_authors=5) == known_output
|
|
163
|
+
|
|
164
|
+
def fillbib_tex(args):
|
|
165
|
+
|
|
166
|
+
if args.bibtex is None: # Get the name of the bibfile from the aux file
|
|
167
|
+
basename = args.texfile[0].split('.tex')[0]
|
|
168
|
+
auxfile = basename + '.aux'
|
|
169
|
+
for line in open(auxfile,'r'):
|
|
170
|
+
m = re.search(r'\\bibdata\{(.*)\}',line) # match \citation{...}, collect the ... note that we escape \, {, and }
|
|
171
|
+
if m:
|
|
172
|
+
bibfile = list(filter(lambda x:x!=basename+'Notes', m.group(1).split(',')))[0] # Remove that annyoing feature of revtex which creates a *Notes.bib bibfile. Note this is not solid if you want to handle multiple bib files.
|
|
173
|
+
bibfile = bibfile + '.bib'
|
|
174
|
+
|
|
175
|
+
else: # Bibfile specified from argv
|
|
176
|
+
basename = args.texfile[0].split('.tex')[0]
|
|
177
|
+
auxfile = basename + '.aux'
|
|
178
|
+
bibfile = args.bibtex.split('.bib')[0] + '.bib'
|
|
179
|
+
|
|
180
|
+
if args.updatepublished:
|
|
181
|
+
with open(basename+".tex", 'r') as texfile:
|
|
182
|
+
texdata = texfile.read()
|
|
183
|
+
|
|
184
|
+
# Get all citations from aux file. Citations will look like \citation{2004PhRvD..69j4017P,2004PhRvD..69j4017P}
|
|
185
|
+
cites = set() # use a set (no repetitions)
|
|
186
|
+
for line in open(auxfile,'r'):
|
|
187
|
+
m = re.search(r'\\citation\{(.*)\}',line) # find \citation{...}
|
|
188
|
+
if m:
|
|
189
|
+
cites.update(m.group(1).split(',')) # split by commas
|
|
190
|
+
|
|
191
|
+
cites= cites.difference([
|
|
192
|
+
'REVTEX41Control','apsrev41Control',
|
|
193
|
+
'REVTEX42Control','apsrev42Control']) # Remove annoying entries of revtex
|
|
194
|
+
|
|
195
|
+
print("Seek:", cites)
|
|
196
|
+
|
|
197
|
+
# Check what you already have in the bib file
|
|
198
|
+
haves = []
|
|
199
|
+
if os.path.isfile(bibfile):
|
|
200
|
+
for line in open(bibfile,'r'):
|
|
201
|
+
m = re.search(r'@.*?\{(.*),',line) # .*\{ means "any # of any char followed by {"; .*?\{ means "the shortest string matching any # of any char followed by {"
|
|
202
|
+
if m:
|
|
203
|
+
haves.append(m.group(1))
|
|
204
|
+
print("Have:", haves)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# Query ADS and INSPIRE
|
|
208
|
+
bibtex = open(bibfile,'a') # open for appending
|
|
209
|
+
|
|
210
|
+
for c in cites:
|
|
211
|
+
if c and c not in haves: # c is something and you don't have it already
|
|
212
|
+
|
|
213
|
+
if not c[0].isalpha(): # The first charachter is a number: could be on ADS
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
bib = ads_citation(c)
|
|
217
|
+
|
|
218
|
+
cfound = bib.split("{")[1].split(',')[0]
|
|
219
|
+
|
|
220
|
+
if cfound == c: # Check you got what you where looking for
|
|
221
|
+
pass
|
|
222
|
+
elif 'arXiv' in c: # Take care of preprint on ADS
|
|
223
|
+
|
|
224
|
+
if args.updatepublished and '.tmp.' not in cfound:
|
|
225
|
+
print("ADS replace", c, "-->", cfound)
|
|
226
|
+
# This substitute the new ID into the tex file. Use at your own risk. The .tmp. condition fixes those stupid MNRAS temp entries.
|
|
227
|
+
texdata = texdata.replace(c, cfound)
|
|
228
|
+
|
|
229
|
+
else:
|
|
230
|
+
# This subsitute the arxiv id back in to the bib file
|
|
231
|
+
bib = bib.split("{")[0]+"{"+c+","+",".join(bib.split(",")[1:])
|
|
232
|
+
|
|
233
|
+
bibtex.write(bib)
|
|
234
|
+
print("ADS Found:", c)
|
|
235
|
+
except:
|
|
236
|
+
print("ADS Not found:", c)
|
|
237
|
+
|
|
238
|
+
else: # The first charachter is not a number: could be on INSPIRE
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
bib = inspire_citation(c,
|
|
242
|
+
generate=args.generate,
|
|
243
|
+
max_num_authors=args.max_num_authors,
|
|
244
|
+
num_authors_short=args.num_authors_short,
|
|
245
|
+
journal_arXiv_fallback=args.journal_arXiv_fallback)
|
|
246
|
+
bibtex.write(bib)
|
|
247
|
+
print("INSPIRE Found:", c)
|
|
248
|
+
except:
|
|
249
|
+
print("INSPIRE Not found:", c)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
bibtex.close()
|
|
254
|
+
|
|
255
|
+
if args.updatepublished:
|
|
256
|
+
with open(basename+".tex", 'w') as texfile:
|
|
257
|
+
texfile.write(texdata)
|
|
258
|
+
|
|
259
|
+
# Clean up journal names
|
|
260
|
+
if args.journals:
|
|
261
|
+
journals(bibfile)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def fillbib_list(args):
|
|
265
|
+
for c in args.keys:
|
|
266
|
+
if not c[0].isalpha():
|
|
267
|
+
bib = ads_citation(c)
|
|
268
|
+
if bib is None:
|
|
269
|
+
sys.stderr.write("ADS Not Found: {}\n".format(c))
|
|
270
|
+
else:
|
|
271
|
+
print(bib)
|
|
272
|
+
else:
|
|
273
|
+
bib = inspire_citation(c,
|
|
274
|
+
generate=args.generate,
|
|
275
|
+
max_num_authors=args.max_num_authors,
|
|
276
|
+
num_authors_short=args.num_authors_short,
|
|
277
|
+
journal_arXiv_fallback=args.journal_arXiv_fallback)
|
|
278
|
+
if bib is None:
|
|
279
|
+
sys.stderr.write("INSPIRE Not Found: {}\n".format(c))
|
|
280
|
+
else:
|
|
281
|
+
print(bib)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def curly(x):
|
|
285
|
+
'''Just a curly bracket sandwich.'''
|
|
286
|
+
return "{"+x+"}"
|
|
287
|
+
|
|
288
|
+
def journals(bibfile):
|
|
289
|
+
'''
|
|
290
|
+
Clean up the names of some journals using their ISO4 standards.
|
|
291
|
+
Journal abbreviations are taken from https://images.webofknowledge.com/images/help/WOS/A_abrvjt.html
|
|
292
|
+
If your favourite journal is missing, please add it and send a pull request. Thanks!
|
|
293
|
+
'''
|
|
294
|
+
|
|
295
|
+
# The format is: [ADS name, INSPIRE name, ISO4 abbreviation]
|
|
296
|
+
journals = [
|
|
297
|
+
####
|
|
298
|
+
# These are the journals from the ADS macros: https://ui.adsabs.harvard.edu/help/actions/journal-macros
|
|
299
|
+
# I could not find them all on INSPIRE, some are missing.
|
|
300
|
+
####
|
|
301
|
+
['\\aj', 'Astron. J.', 'Astron. J.'],
|
|
302
|
+
['\\actaa', 'Acta Astron.', 'Acta Astronom.'],
|
|
303
|
+
['\\araa', 'Ann. Rev. Astron. Astrophys.', 'Annu. Rev. Astron. Astrophys.'],
|
|
304
|
+
['\\apj', 'Astrophys. J.', 'Astrophys. J.'],
|
|
305
|
+
['\\apjl', 'Astrophys. J. Lett.', 'Astrophys. J. Lett.'],
|
|
306
|
+
['\\apjs', 'Astrophys. J. Suppl.', 'Astrophys. J. Supp. S.'],
|
|
307
|
+
['\\ao', 'Appl. Opt.', 'Appl. Optics'],
|
|
308
|
+
['\\apss', 'Astrophys. Space Sci.', 'Astrophys. Space Sci.'],
|
|
309
|
+
['\\aap', 'Astron. Astrophys.', 'Astron. Astrophys.'],
|
|
310
|
+
['\\aapr', 'Astron. Astrophys. Rev.', 'Astron. Astrophys. Rev.'],
|
|
311
|
+
['\\aaps', 'Astron. Astrophys. Suppl. Ser.', 'Astron. Astrophys. Sup.'],
|
|
312
|
+
['\\azh', '', 'Astron. Zh.'], #Not sure. Various names on inspire
|
|
313
|
+
['\\baas', 'Bull. Am. Astron. Soc.', 'Bull. Am. Astron. Soc.'],
|
|
314
|
+
['\\bac', 'Bull. Astron. Inst. Czech.', 'B. Astron. I. Czech.'],
|
|
315
|
+
['\\caa', 'Chin. Astron. Astrophys.', 'Chinese Astron. Astr.'],
|
|
316
|
+
['\\cjaa', 'Chin. J. Astron. Astrophys.', 'Chinese J. Astron. Ast.'],
|
|
317
|
+
['\\icarus', 'Icarus', 'Icarus'],
|
|
318
|
+
['\\jcap', 'JCAP', 'J. Cosmology Astropart. Phys.'],
|
|
319
|
+
['\\jrasc', 'J. Roy. Astron. Soc. Canada', 'J. Roy Astron. Soc. Can.'],
|
|
320
|
+
['\\memras', 'Mem. Roy. Astron. Soc.', 'Mem. R. Astron. Soc.'],
|
|
321
|
+
['\\mnras', 'Mon. Not. Roy. Astron. Soc.', 'Mon. Not. R. Astron. Soc.'],
|
|
322
|
+
['\\na', 'New Astron.', 'New Astron.'],
|
|
323
|
+
['\\nar', 'New Astron. Rev.', 'New Astron. Rev.'],
|
|
324
|
+
['\\pra', 'Phys. Rev. A', 'Phys. Rev. A'],
|
|
325
|
+
['\\prb', 'Phys. Rev. B', 'Phys. Rev. B'],
|
|
326
|
+
['\\prc', 'Phys. Rev. C', 'Phys. Rev. C'],
|
|
327
|
+
['\\prd', 'Phys. Rev. D', 'Phys. Rev. D'],
|
|
328
|
+
['\\pre', 'Phys. Rev. E', 'Phys. Rev. E'],
|
|
329
|
+
['\\prl', 'Phys. Rev. Lett.', 'Phys. Rev. Lett.'],
|
|
330
|
+
['\\pasa', 'Publ. Astron. Soc. Austral.', 'Publ. Astron. Soc. Aust.'],
|
|
331
|
+
['\\pasp', 'Publ. Astron. Soc. Pac.', 'Publ. Astron. Soc. Pac.'],
|
|
332
|
+
['\\pasj', 'Publ. Astron. Soc. Jap.', 'Publ. Astron. Soc. Jpn.'],
|
|
333
|
+
['\\rmxaa', 'Rev. Mex. Astron. Astrofis.', 'Rev. Mex. Astron. Astr.'],
|
|
334
|
+
['\\qjras', 'Q. J. Roy. Astron. Soc.', 'Q. J. Roy. Astron. Soc.'],
|
|
335
|
+
['\\skytel', 'Sky Telesc.', 'Sky Telescope'],
|
|
336
|
+
['\\solphys', 'Solar Phys.', 'Sol. Phys.'],
|
|
337
|
+
['\\sovast', 'Sov. Astron.', 'Sov. Astron.'],
|
|
338
|
+
['\\ssr', 'Space Sci. Rev.', 'Space Sci. Rev.'],
|
|
339
|
+
['\\zap', 'Z. Astrophys.', 'Z. Astrophys.'],
|
|
340
|
+
['\\nat', 'Nature', 'Nature'],
|
|
341
|
+
['\\iaucirc', 'IAU Circ.', 'IAU Circ.'],
|
|
342
|
+
['\\aplett', 'Astrophys. Lett.', 'Astrophys. Lett.'],
|
|
343
|
+
['\\apspr', '', 'Astrophys.~Space~Phys.~Res.'], #Could not find it on INSPIRE
|
|
344
|
+
['\\bain', 'Bull. Astron. Inst. Netherlands', 'B. Astron. I. Neth.'],
|
|
345
|
+
['\\fcp', 'Fund. Cosmic Phys.', 'Fund. Cosmic Phys.'],
|
|
346
|
+
['\\gca', 'Geochim. Cosmochim. Acta', 'Geochim. Cosmochim. Ac.'],
|
|
347
|
+
['\\grl', 'Geophys. Res. Lett.', 'Geophys. Res. Lett.'],
|
|
348
|
+
['\\jcp', 'J. Chem. Phys.', 'J. Chem. Phys.'],
|
|
349
|
+
['\\jgr', 'J. Geophys. Res.', 'J. Geophys. Res.'],
|
|
350
|
+
['\\jqsrt', 'J. Quant. Spectrosc. Radiat. Trans.', 'J. Quant. Sprectrosc. Ra.'],
|
|
351
|
+
['\\memsai', 'Mem. Soc. Ast. It.', 'Mem. Soc. Astron. Ital.'],
|
|
352
|
+
['\\nphysa', 'Nucl. Phys. A', 'Nucl. Phys. A'],
|
|
353
|
+
['\\physrep', 'Phys. Rept.', 'Phys. Rep.'],
|
|
354
|
+
['\\physscr', 'Phys. Scripta', 'Phys. Scripta'],
|
|
355
|
+
['\\planss', 'Planet. Space Sci.', 'Planet. Space Sci.'],
|
|
356
|
+
['\\procspie', 'Proc. SPIE Int. Soc. Opt. Eng.', 'P. Soc. Photo.-Opt. Ins.'],
|
|
357
|
+
####
|
|
358
|
+
# [Davide Gerosa] These are journals that I personally encountered.
|
|
359
|
+
# Will keep on adding to this list.
|
|
360
|
+
####
|
|
361
|
+
['Advances in Space Research','Adv. Space Res.','Adv. Space Res.'], #ISI list not correct
|
|
362
|
+
['American Institute of Physics Conference Series','AIP Conf. Proc.','AIP Conf. Proc.'],
|
|
363
|
+
['Annals of Data Science','Ann. Data Sci.','Ann. Data Sci.'],
|
|
364
|
+
['Astronomy and Computing','Astron. Comput.','Astron. Comput.'],
|
|
365
|
+
['Astroparticle Physics','Astropart. Phys.','Astropart. Phys.'],
|
|
366
|
+
['Astrophysics and Space Science Library','Astrophys. Space Sci. Libr.','Astrophys. Space Sc. L.'],
|
|
367
|
+
['Astrophysics and Space Science Library','Astrophys. Space Sci. Libr.','Astrophys. Space Sc. L.'],
|
|
368
|
+
['Bulletin of the American Astronomical Society','Bull. Am. Astron. Soc.','Bull. Am. Astron. Soc.'],
|
|
369
|
+
['Classical and Quantum Gravity','Class. Quant. Grav.','Class. Quantum Grav.'], #ISI list not correct
|
|
370
|
+
['Communications in Mathematical Physics', 'Commun. Math. Phys.', 'Commun. Math. Phys.'],
|
|
371
|
+
['Frontiers in Astronomy and Space Sciences','Front. Astron. Space Sci.','Front. Astron. Space Sci.'],
|
|
372
|
+
['General Relativity and Gravitation', 'Gen. Rel. Grav.', 'Gen. Relat. Gravit.'],
|
|
373
|
+
['International Journal of Modern Physics D', 'Int. J. Mod. Phys. D', 'Int. J. Mod. Phys. D'],
|
|
374
|
+
['iScience', 'iScience', 'iScience'],
|
|
375
|
+
['Journal of High Energy Physics','JHEP','J. High Energy Phys.'],
|
|
376
|
+
['Journal of Machine Learning Research','J. Machine Learning Res.','J. Mach. Learn. Res.'],
|
|
377
|
+
['Journal of Mathematical Analysis and Applications','J. Math. Anal. Appl.','J. Math. Anal. Appl'],
|
|
378
|
+
['Journal of Physics Conference Series','J. Phys. Conf. Ser.','J. Phys. Conf. Ser.'],
|
|
379
|
+
['Journal of Statistical Physics','J. Statist. Phys.','J. Stat. Phys.'],
|
|
380
|
+
['Journal of the Royal Statistical Society B','J. Roy. Statist. Soc. B','J. Roy. Statist. Soc. B'],
|
|
381
|
+
['Living Reviews in Relativity', 'Living Rev. Rel.', 'Living Rev. Relativ.'],
|
|
382
|
+
['Machine Learning: Science and Technology','Mach. Learn. Sci. Tech.','Mach. Learn. Sci. Tech.'], #ISI list not correct
|
|
383
|
+
['Machine Learning','Machine Learning','Mach. Learn.'],
|
|
384
|
+
['Nature Astronomy', 'Nature Astron.', 'Nat. Astron.'],
|
|
385
|
+
['Nature Methods', 'Nature Meth.', 'Nat. Methods'],
|
|
386
|
+
['Nature Reviews Physics','Nature Rev. Phys.','Nat. Rev. Phys.'],
|
|
387
|
+
['Physica A Statistical Mechanics and its Applications','Physica A','Physica A'],
|
|
388
|
+
['Physica D Nonlinear Phenomena', 'Physica D', 'Physica D'],
|
|
389
|
+
['Physical Review', 'Phys. Rev.', 'Phys. Rev.'],
|
|
390
|
+
['Physical Review Research', 'Phys. Rev. Res.', 'Phys. Rev. Res.'],
|
|
391
|
+
['Physical Review X', 'Phys. Rev. X', 'Phys. Rev. X'],
|
|
392
|
+
['Physics Letters A', 'Phys. Lett. A', 'Phys. Lett. A'],
|
|
393
|
+
['Proceedings of the Royal Society of London Series A', 'Proc. Roy. Soc. Lond. A', 'P. R. Soc. Lond. A'],
|
|
394
|
+
['Rendiconti Lincei. Scienze Fisiche e Naturali', 'Rend. Lincei Sci. Fis. Nat.', 'Rend. Lincei-Sci. Fis.'],
|
|
395
|
+
['Reports on Progress in Physics', 'Rept. Prog. Phys.', 'Rep. Prog. Phys.'],
|
|
396
|
+
['Research Notes of the American Astronomical Society', 'Res. Notes AAS','Res. Notes AAS'],
|
|
397
|
+
['Reviews of Modern Physics', 'Rev. Mod. Phys.', 'Rev. Mod. Phys.'],
|
|
398
|
+
['Science Advances','Sci. Adv.','Sci. Adv.'],
|
|
399
|
+
['SIAM Journal on Scientific Computing','SIAM J. Sci. Comput.','SIAM J. Sci. Comput.'],
|
|
400
|
+
['The Journal of Open Source Software','J. Open Source Softw.','J. Open Source Softw.'],
|
|
401
|
+
]
|
|
402
|
+
|
|
403
|
+
with open(bibfile, 'r') as bibtex :
|
|
404
|
+
filedata = bibtex.read()
|
|
405
|
+
|
|
406
|
+
for j in journals:
|
|
407
|
+
print(j)
|
|
408
|
+
if j[0]:
|
|
409
|
+
filedata = filedata.replace(curly(j[0]), curly(j[2]))
|
|
410
|
+
if j[1]:
|
|
411
|
+
filedata = filedata.replace(curly(j[1]), curly(j[2]))
|
|
412
|
+
filedata = filedata.replace('journal = "'+j[1], 'journal = "'+j[2])
|
|
413
|
+
|
|
414
|
+
### Clean up arxiv repeated information in ADS records:
|
|
415
|
+
filedata = filedata.replace('arXiv e-prints', '{}')
|
|
416
|
+
filedata = re.sub('pages = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
417
|
+
filedata = re.sub('Pages = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
418
|
+
filedata = re.sub('eid = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
419
|
+
filedata = re.sub('Eid = {arXiv:[0-9]+.[0-9]+},','',filedata)
|
|
420
|
+
filedata = re.sub('doi = {[0-9]+.[0-9]+/arXiv.[0-9]+.[0-9]+},','',filedata)
|
|
421
|
+
|
|
422
|
+
with open(bibfile, 'w') as bibtex :
|
|
423
|
+
bibtex.write(filedata)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
if __name__ == "__main__":
|
|
429
|
+
|
|
430
|
+
parser = argparse.ArgumentParser()
|
|
431
|
+
parser.add_argument("--generate", action="store_true",
|
|
432
|
+
help="Generate the BibTeX entries from the metadata "
|
|
433
|
+
"(this is useful to customize the generated BiBTeX file)")
|
|
434
|
+
parser.add_argument("--journal_arXiv_fallback", dest="journal_arXiv_fallback", action="store_true",
|
|
435
|
+
help="Set the journal entry to be arXiv for unpublished preprints "
|
|
436
|
+
"(iNSPIRE entries only, requres --generate)")
|
|
437
|
+
parser.add_argument("--max-num-authors", dest="max_num_authors", type=int,
|
|
438
|
+
help="Include at most this many authors for each bibtex entry"
|
|
439
|
+
"(iNSPIRE entries only, requres --generate)")
|
|
440
|
+
parser.add_argument("--num-authors-short", type=int,
|
|
441
|
+
help="Number of authors to list if the number of authors is larger than max_num_authors"
|
|
442
|
+
"(iNSPIRE entries only, defaults to max-num-authors, requres --generate)")
|
|
443
|
+
subparsers = parser.add_subparsers(help="Subcommands")
|
|
444
|
+
|
|
445
|
+
parser_tex = subparsers.add_parser("tex", help="Create a bibliography for a tex document")
|
|
446
|
+
parser_tex.add_argument("--bibtex", help="The BiBTeX file to use (if not specified we try to find out)")
|
|
447
|
+
parser_tex.add_argument("texfile", nargs=1, help="The (La)TeX file to process")
|
|
448
|
+
parser_tex.add_argument('--journals', dest='journals', help="Replace known journal abbreviations", default=True, action='store_true')
|
|
449
|
+
parser_tex.add_argument('--updatepublished', dest='updatepublished', help="Replace ADS arxiv entries in .tex file if published", default=True, action='store_true')
|
|
450
|
+
parser_tex.set_defaults(func=fillbib_tex)
|
|
451
|
+
|
|
452
|
+
parser_list = subparsers.add_parser("list", help="Create a bibliography given a list of ADS/iNSPIRE keys")
|
|
453
|
+
parser_list.add_argument("keys", nargs="+", help="ADS/iNSPIRE keys to fetch")
|
|
454
|
+
parser_list.set_defaults(func=fillbib_list)
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
args = parser.parse_args()
|
|
458
|
+
args.func(args)
|
|
459
|
+
#try:
|
|
460
|
+
# args.func(args)
|
|
461
|
+
#except:
|
|
462
|
+
# parser.print_usage()
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Full tex compiler: run pdflatex, bibtex, query ADS and INSPIRE for citations and count words
|
|
3
|
+
# Davide Gerosa
|
|
4
|
+
|
|
5
|
+
# Install texshop engine
|
|
6
|
+
if [[ $1 = 'install-texshop' ]]; then
|
|
7
|
+
TEXSHOP="${HOME}/Library/TeXshop/Engines/filltex.engine"
|
|
8
|
+
echo "Installing texshop engine in $TEXSHOP"
|
|
9
|
+
echo ''#!/bin/bash '' > $TEXSHOP
|
|
10
|
+
echo ''export PATH=$(dirname $(which filltex)):\${PATH}'' >> $TEXSHOP
|
|
11
|
+
echo ''echo \$1 '' >> $TEXSHOP
|
|
12
|
+
echo ''FILENAME=\${1%%.*} '' >> $TEXSHOP
|
|
13
|
+
echo ''echo \$FILENAME '' >> $TEXSHOP
|
|
14
|
+
echo ''filltex \$FILENAME '' >> $TEXSHOP
|
|
15
|
+
chmod +x $TEXSHOP
|
|
16
|
+
exit
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Actual script
|
|
21
|
+
#SCRIPT=`realpath $0`
|
|
22
|
+
#SCRIPT_LOCATION=`dirname $SCRIPT`
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
START=$PWD #Where you started
|
|
26
|
+
|
|
27
|
+
if [ ! -f ${START}/${1%.*}.tex ]; then
|
|
28
|
+
echo "File not found!"
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
FILE=${1%.*}
|
|
32
|
+
echo "filltex is compiling ${FILE}.tex"
|
|
33
|
+
|
|
34
|
+
# Get the journal abbreviations from ADS
|
|
35
|
+
if grep -q 'aas_macros' ${FILE}.tex; then # check if you need them
|
|
36
|
+
if [ ! -f 'aas_macros.sty' ]; then
|
|
37
|
+
curl -s 'https://adsabs.harvard.edu/abs_doc/aas_macros.sty' > 'aas_macros.sty'
|
|
38
|
+
fi
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# The pdflatex command returns 0 if everyting is ok, or 1 if he gets an error. If there's an error, I want the script to exit.
|
|
42
|
+
pdflatex --synctex=1 -halt-on-error ${FILE}.tex
|
|
43
|
+
[[ $? -eq 1 ]] && echo "pdflatex got an error" && exit
|
|
44
|
+
|
|
45
|
+
# Fill the bib fil with the ADS and INSPIRE references.
|
|
46
|
+
# Use python 2
|
|
47
|
+
#python ${SCRIPT_LOCATION}/fillbib.py "${FILE}"
|
|
48
|
+
# Use python 3
|
|
49
|
+
#python3 ${SCRIPT_LOCATION}/fillbib.py "${FILE}"
|
|
50
|
+
#python ../filltex/fillbib.py tex ${FILE}
|
|
51
|
+
fillbib tex ${FILE}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
for i in {1..2}; do
|
|
55
|
+
|
|
56
|
+
# Fill the bbl file from the bib file
|
|
57
|
+
for file in *.aux ; do
|
|
58
|
+
bibtex $file
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
pdflatex --synctex=1 -halt-on-error ${FILE}.tex
|
|
62
|
+
[[ $? -eq 1 ]] && echo "pdflatex got an error" && exit
|
|
63
|
+
|
|
64
|
+
pdflatex --synctex=1 -halt-on-error ${FILE}.tex
|
|
65
|
+
[[ $? -eq 1 ]] && echo "pdflatex got an error" && exit
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
# Count the words
|
|
69
|
+
#perl ${SCRIPT_LOCATION}/texcount.pl "${FILE}".tex
|
|
70
|
+
texcount "${FILE}".tex
|
|
71
|
+
|
|
72
|
+
# open the pdf file if you like
|
|
73
|
+
#open "${FILE}".pdf
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: filltex
|
|
3
|
+
Version: 1.7.0
|
|
4
|
+
Summary: Automatic queries to ADS and InSPIRE databases to fill LATEX bibliography
|
|
5
|
+
Home-page: https://github.com/dgerosa/filltex
|
|
6
|
+
Author: Davide Gerosa and Michele Vallisneri
|
|
7
|
+
Author-email: dgerosa@star.sr.bham.ac.uk
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Dynamic: author
|
|
11
|
+
Dynamic: author-email
|
|
12
|
+
Dynamic: description
|
|
13
|
+
Dynamic: home-page
|
|
14
|
+
Dynamic: license
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
Dynamic: summary
|
|
17
|
+
|
|
18
|
+
See: `github.com/dgerosa/filltex <https://github.com/dgerosa/filltex>`_.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
fillbib.py,sha256=ypKf452OmfHToVtEMDTG2cBRG8_OWDwdCHDaSgooGnU,22636
|
|
2
|
+
filltex-1.7.0.data/scripts/fillbib,sha256=lj_39ocfku8_MfdL8XVkc9k11eWhzyyrrC9HcuQv0PM,22623
|
|
3
|
+
filltex-1.7.0.data/scripts/filltex,sha256=cwUCJB2vxM_aUnH5ELC_DyDhuA-k4G3mYiKnQeWMnvk,2025
|
|
4
|
+
filltex-1.7.0.dist-info/licenses/LICENSE,sha256=02z8PApk_0N4ZQ8_rKArOOzClS7B0i4wNurOuUlHG0w,1070
|
|
5
|
+
filltex-1.7.0.dist-info/METADATA,sha256=TGugmQARK4iqVZDSbZ6hg2DearLVN0QADrBYxT5r_TI,509
|
|
6
|
+
filltex-1.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
filltex-1.7.0.dist-info/top_level.txt,sha256=dsEFVd7-rpq7Y4b2xsbUT1rUMnS46mx4cN6EnytACpI,8
|
|
8
|
+
filltex-1.7.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Davide Gerosa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fillbib
|