sxs 2024.0.2__py3-none-any.whl → 2024.0.3__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.
sxs/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2024.0.2"
1
+ __version__ = "2024.0.3"
sxs/utilities/__init__.py CHANGED
@@ -38,6 +38,7 @@ from .smooth_functions import (
38
38
  transition_to_constant, transition_to_constant_inplace,
39
39
  bump_function, bump_function_inplace
40
40
  )
41
+ from .inspire import inspire2doi
41
42
 
42
43
 
43
44
  def version_info():
sxs/utilities/inspire.py CHANGED
@@ -1,229 +1,153 @@
1
1
  """Search the INSPIRE database
2
2
 
3
- Documentation can be found here: <https://inspirehep.net/info/hep/api>
3
+ Documentation can be found here: <https://github.com/inspirehep/rest-api-doc>
4
4
 
5
5
  """
6
6
 
7
- from functools import lru_cache
7
+ import warnings
8
8
 
9
- api_url = "https://inspirehep.net/search"
9
+ api_url = "https://inspirehep.net/api/{record_type}"
10
10
 
11
11
 
12
- @lru_cache()
13
- def query(pattern, output_format='recjson', output_tags=None, records_in_groups_of=None, jump_to_records=None):
14
- """Search the INSPIRE database
15
-
16
- API documentation: <https://inspirehep.net/info/hep/api>
17
- Search documentation: <https://inspirehep.net/info/hep/search-tips>
12
+ def inspire2doi(inspire_bibtex_key, raise_exceptions=False):
13
+ try:
14
+ result = query(inspire_bibtex_key, fields="dois.value,arxiv_eprints")
15
+ except KeyboardInterrupt:
16
+ raise
17
+ except Exception as e:
18
+ warnings.warn(f"Error querying for INSPIRE key {inspire_bibtex_key}")
19
+ if raise_exceptions:
20
+ raise e
21
+ else:
22
+ if not result:
23
+ warnings.warn(f"No entry found for INSPIRE key {inspire_bibtex_key}")
24
+ if raise_exceptions:
25
+ raise ValueError(f"No entry found for INSPIRE key {inspire_bibtex_key}")
26
+ else:
27
+ try:
28
+ return result[0]["metadata"]["dois"][0]["value"]
29
+ except Exception as e:
30
+ # DOI not present; INSPIRE only has an arXiv number, so we'll convert to an arXiv DOI
31
+ try:
32
+ eprint_value = result[0]["metadata"]["arxiv_eprints"][0]["value"]
33
+ # https://info-arxiv-org.proxy.library.cornell.edu/help/arxiv_identifier.html
34
+ # says that identifiers starting with 9107 to 0703 need their category included
35
+ if eprint_value.startswith("9") or int(eprint_value[:4])<704:
36
+ category = result[0]["metadata"]["arxiv_eprints"][0]["categories"][0]
37
+ return f"10.48550/arXiv.{category}/{eprint_value}"
38
+ else:
39
+ return f"10.48550/arXiv.{eprint_value}"
40
+ except Exception as e:
41
+ warnings.warn(f"Unexpected result format for INSPIRE key {inspire_bibtex_key}: \n{result}")
42
+ if raise_exceptions:
43
+ raise e
44
+
45
+
46
+ def query(
47
+ query,
48
+ sort="mostrecent",
49
+ page=1,
50
+ size=1000,
51
+ fields=None,
52
+ page_limit=10,
53
+ record_type="literature"
54
+ ):
55
+ """Fetch records from the INSPIRE API.
18
56
 
19
57
  Parameters
20
58
  ----------
21
- pattern : str
22
- This is the query in the Inspire search syntax. All search features and
23
- operators familiar from the Inspire web interface and documented in the
24
- online help are supported and complex queries are possible. Documentation
25
- here: <https://inspirehep.net/info/hep/search-tips>.
26
- output_format : str, optional [defaults to 'recjson']
27
- The format of the response sent back to the client. There are two choices,
28
- 'xm' for (MARC-)XML or 'recjson' for JSON. The XML response format is
29
- MARCXML or fragments thereof when individual fields are selected via the
30
- output_tags parameter
31
- output_tags : str, optional [defaults to None]
32
- If present, this selects (filter) specific tags from the response. If
33
- output_format is 'xm', this option takes a comma separated list of MARC
34
- tags; valid MARC tags for Inspire records can be found here
35
- <https://twiki.cern.ch/twiki/bin/view/Inspire/DevelopmentRecordMarkup>. If
36
- output_format is 'recjson', this is similar to selecting MARC tags, however
37
- by name instead of numerical value. In addition the JSON response can
38
- contain derived or dynamically calculated values which are not available in
39
- MARC. If this argument is None, the default output will be returned, which
40
- generally includes all available information for each record.
41
- records_in_groups_of : int, optional [defaults to None]
42
- If present, this parameter specifies the number of records per chunk for
43
- long responses. Note that the default setting is 25 records per chunk. The
44
- maximum number is 250.
45
- jump_to_records : int, optional [defaults to None]
46
- Long responses are split into several chunks. To access subsequent chunks
47
- specify the record offset with this parameter.
48
-
59
+ query : str
60
+ The search query. For details, see
61
+ https://github.com/inspirehep/rest-api-doc/tree/master#search-query
62
+ fields : str, optional
63
+ The fields to retrieve from INSPIRE. This can be a
64
+ comma-separated list of field names. For example, to
65
+ retrieve the list of DOIs: "dois.value". Other options at
66
+ https://inspire-schemas.readthedocs.io/en/latest/schemas/elements/reference.html
67
+ Note that other fields will also be returned for each record,
68
+ even when you just ask for one — including "id", "links",
69
+ "metadata", "created", and "updated". The default value of
70
+ None will return all fields.
71
+ sort : str, optional
72
+ The sorting order. Default is "mostrecent".
73
+ size : int, optional
74
+ The number of records per page. Default is 1000.
75
+ page : int, optional
76
+ The starting page number. Default is 1.
77
+ page_limit : int, optional
78
+ Optional limit to the number of pages to collect.
79
+ record_type : str, optional
80
+ The type of record to fetch (e.g., "literature"). Default is
81
+ "literature". Other options can be found here:
82
+ https://github.com/inspirehep/rest-api-doc/tree/master#obtaining-a-record
83
+
49
84
  Returns
50
85
  -------
51
- json : list or dict
52
- Usually, this will be a list of the results from the query, even if there
53
- is only one. Each result will be a dictionary mapping the requested
54
- 'output_tags' to their corresponding values.
86
+ list
87
+ The JSON response from the API.
55
88
 
56
89
  Raises
57
90
  ------
58
91
  requests.exceptions.HTTPError :
59
- If the HTTP request to INSPIRE failed for any reason
92
+ If the HTTP request to INSPIRE failed
60
93
 
61
94
  """
62
95
  import sys
63
96
  import requests
64
-
97
+ from requests.adapters import HTTPAdapter
98
+ from urllib3.util.retry import Retry
99
+
100
+ session = requests.Session()
101
+ collected_results = []
102
+
103
+ ## Retry automatically on certain types of errors
104
+ retry = Retry(
105
+ total=10,
106
+ backoff_factor=0.1,
107
+ status_forcelist=[
108
+ 413, # Request Entity Too Large
109
+ 429, # Too Many Requests
110
+ 500, # Internal Server Error
111
+ 502, # Bad Gateway
112
+ 503, # Service Unavailable
113
+ 504, # Gateway Timeout
114
+ ],
115
+ )
116
+ adapter = HTTPAdapter(max_retries=retry)
117
+ session.mount("https://", adapter)
118
+
119
+ url = api_url.format(record_type=record_type)
65
120
  params = {
66
- 'p': pattern,
67
- 'of': output_format,
68
- }
69
- if output_tags is not None:
70
- params['ot'] = output_tags
71
- if records_in_groups_of is not None:
72
- params['rg'] = records_in_groups_of
73
- if jump_to_records is not None:
74
- params['jrec'] = jump_to_records
75
-
76
- r = requests.get(api_url, params=params)
77
- if r.status_code != 200:
78
- print('An error occurred when trying to access <{0}>.'.format(api_url), file=sys.stderr)
79
- try:
80
- print(r.json(), file=sys.stderr)
81
- except:
82
- pass
83
- r.raise_for_status()
84
- raise RuntimeError() # Will only happen if the response was not strictly an error
85
- return r.json()
86
-
87
-
88
- def extract_bibtex_key(system_control_numbers):
89
- """Get bibtex key from 'system_control_numbers' field
90
-
91
- Unfortunately, this seems to be the only way to get the bibtex key. I have
92
- seen suggestions around the github issues for inspirehep/invenio that this
93
- should always be present
94
-
95
- """
96
- if isinstance(system_control_numbers, dict):
97
- system_control_numbers = [system_control_numbers,]
98
- bibtex_keys = [number.get('value', '') for number in system_control_numbers
99
- if number.get('institute', '') in ['INSPIRETeX', 'SPIRESTeX']]
100
- bibtex_keys = [key for key in bibtex_keys if key]
101
- if not bibtex_keys:
102
- return ''
103
- return bibtex_keys[0]
104
-
105
-
106
- def extract_doi(doi):
107
- """Ensure that 'doi' is a single string
108
-
109
- Occasionally, INSPIRE returns a list of identical DOIs. This just extracts the
110
- first element if it is such a list, or returns the input otherwise.
111
-
112
- """
113
- if isinstance(doi, list) and len(doi)>0:
114
- return doi[0]
115
- return doi
116
-
117
-
118
- def extract_doi_url(doi):
119
- """Ensure that 'doi' is a single string
120
-
121
- Occasionally, INSPIRE returns a list of identical DOIs. This just extracts the
122
- first element if it is such a list, or returns the input otherwise.
123
-
124
- """
125
- doi = extract_doi(doi)
126
- if doi:
127
- return 'https://dx.doi.org/' + doi
128
- else:
129
- return doi
130
-
131
-
132
- def extract_arxiv_url(system_control_numbers):
133
- """Extract any arxiv URLs from the system_control_number field
134
-
135
- """
136
- if isinstance(system_control_numbers, dict):
137
- system_control_numbers = [system_control_numbers,]
138
- arxiv_urls = [
139
- number['value'].replace('oai:arXiv.org:', 'https://arxiv.org/abs/')
140
- for number in system_control_numbers if number.get('institute', '') == 'arXiv' and 'value' in number
141
- ]
142
- if not arxiv_urls:
143
- return ''
144
- return arxiv_urls[0]
145
-
146
-
147
- def map_bibtex_keys_to_doi(bibtex_keys):
148
- """Map a list of INSPIRE bibtex keys to DOIs
149
-
150
- This function queries the INSPIRE database, searching for each of the input
151
- bibtex keys, and extracting the corresponding DOIs (if present on INSPIRE).
152
-
153
- Parameter
154
- ---------
155
- bibtex_keys : str, or list of str
156
- Each string should be precisely one bibtex key from INSPIRE. Note that any
157
- bibtex keys that are not found by INSPIRE are simply ignored.
158
-
159
- Returns
160
- -------
161
- key_to_doi : dict
162
- The output is a dictionary mapping each input bibtex key itself to the
163
- corresponding DOI. These are raw DOIs; to get a URL, just append the DOI
164
- to 'https://dx.doi.org/', which will resolve to the appropriate web page
165
- for that DOI. Note that any record that is found by its bibtex key but
166
- does not have a DOI will simply be absent from this dictionary.
167
-
168
- Raises
169
- ------
170
- requests.exceptions.HTTPError
171
- If the HTTP request to INSPIRE failed for any reason.
172
-
173
- """
174
- if not isinstance(bibtex_keys, list):
175
- bibtex_keys = [bibtex_keys,]
176
- pattern = 'find texkey ' + ' or texkey '.join(bibtex_keys)
177
- output_tags = 'system_control_number,doi'
178
- results = query(pattern, output_tags=output_tags)
179
- mapping = {
180
- bibtex_key: doi
181
- for result in results
182
- for bibtex_key in [extract_bibtex_key(result['system_control_number']),]
183
- for doi in [extract_doi(result['doi']),]
184
- if bibtex_key and doi
121
+ "q": query,
122
+ "sort": sort,
123
+ "size": size,
124
+ "page": page,
185
125
  }
186
- return mapping
187
-
126
+ if fields:
127
+ params["fields"] = fields
128
+
129
+ while params["page"] - page <= page_limit:
130
+ response = session.get(url, params=params)
131
+ if response.status_code != 200:
132
+ print(f"An error occurred when trying to access <{api_url}>.", file=sys.stderr)
133
+ try:
134
+ print(response.json(), file=sys.stderr)
135
+ except:
136
+ pass
137
+ response.raise_for_status()
138
+ raise RuntimeError() # Will only happen if the response was not strictly an error
188
139
 
189
- def map_bibtex_keys_to_identifiers(bibtex_keys):
190
- """Map a list of INSPIRE bibtex keys to DOIs, arxiv numbers, or URLs
191
-
192
- This function queries the INSPIRE database, searching for each of the input
193
- bibtex keys, and extracting the corresponding DOIs (if present on INSPIRE).
194
- Failing that
195
-
196
- Parameter
197
- ---------
198
- bibtex_keys : str, or list of str
199
- Each string should be precisely one bibtex key from INSPIRE. Note that any
200
- bibtex keys that are not found by INSPIRE are simply ignored.
140
+ try:
141
+ json_response = response.json()
142
+ except ValueError:
143
+ print(f"Response from {url} does not contain valid JSON; returning early.")
144
+ return collected_results
201
145
 
202
- Returns
203
- -------
204
- key_to_identifier : dict
205
- The output is a dictionary mapping each input bibtex key itself to the
206
- corresponding DOI URL, arxiv URL, or other URL.
146
+ new_hits = json_response.get("hits", {}).get("hits", [])
147
+ if not new_hits:
148
+ break
149
+ collected_results.extend(new_hits)
207
150
 
208
- Raises
209
- ------
210
- requests.exceptions.HTTPError
211
- If the HTTP request to INSPIRE failed for any reason.
151
+ params["page"] += 1
212
152
 
213
- """
214
- if not bibtex_keys:
215
- return {}
216
- if not isinstance(bibtex_keys, list):
217
- bibtex_keys = [bibtex_keys,]
218
- pattern = 'find texkey ' + ' or texkey '.join(bibtex_keys)
219
- output_tags = 'system_control_number,doi'
220
- results = query(pattern, output_tags=output_tags)
221
- mapping = {
222
- bibtex_key: (doi if doi else arxiv)
223
- for result in results
224
- for bibtex_key in [extract_bibtex_key(result['system_control_number']),]
225
- for doi in [extract_doi_url(result['doi']),]
226
- for arxiv in [extract_arxiv_url(result['system_control_number']),]
227
- if bibtex_key and (bool(doi) or bool(arxiv))
228
- }
229
- return mapping
153
+ return collected_results
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sxs
3
- Version: 2024.0.2
3
+ Version: 2024.0.3
4
4
  Summary: Interface to data produced by the Simulating eXtreme Spacetimes collaboration
5
5
  Project-URL: Homepage, https://github.com/sxs-collaboration/sxs
6
6
  Project-URL: Documentation, https://sxs.readthedocs.io/
@@ -1,5 +1,5 @@
1
1
  sxs/__init__.py,sha256=51_F8xiD6cdE2kIq9dPyHxNQVsp4oCvtR1wQQQ0VS2A,2577
2
- sxs/__version__.py,sha256=yGSQ4W9wNTUhSDstMNJQ4wVLaXLZ87fBrXQzBbbiiV0,25
2
+ sxs/__version__.py,sha256=u5HEtv0zd-O6N1ResGvCK68T1NvJnKchyG62fEdDY5Q,25
3
3
  sxs/handlers.py,sha256=F9XmIhjZm8df1g49fUHemc-9wWstwFUZMacY2RXCWhE,24814
4
4
  sxs/juliapkg.json,sha256=higH1UDu30K_PN6-o7lAz0j1xjgYEiCCYBAc-Iaw1Iw,178
5
5
  sxs/time_series.py,sha256=OKaLg8tFyrtKcef7900ri-a0C6A8wKxA68KovZXvH6I,41081
@@ -20,13 +20,13 @@ sxs/metadata/metadata.py,sha256=_vGqMUbeiN0fecJj9f9f9ex56WgSZuwwBXykUuj1_ZI,2767
20
20
  sxs/simulations/__init__.py,sha256=sl-sDI5N2A03lAfzMig8Jm_Beri_v65qjlIOeGGX9XM,72
21
21
  sxs/simulations/simulation.py,sha256=TaW1wMxbbNjyU9-DrYr65DjlAbtPLPAEoxYtIG6gSkM,21410
22
22
  sxs/simulations/simulations.py,sha256=V1cE966NLCJ2tyowh6S1LrVTGj5KzfLx7RVaUZ5zr_I,16905
23
- sxs/utilities/__init__.py,sha256=NB8v7Hj-ZShSh3pVS_SdZpbPiBrk0nwXjNTHNX1PbFg,4727
23
+ sxs/utilities/__init__.py,sha256=YTyrKYkiDZV4EoT4IHXGBsc_j6RU0aK1c3HERyshVq0,4760
24
24
  sxs/utilities/bitwise.py,sha256=G9ZNYgwDQRhq5wbDf-p2HcUqkEP_IRDiQoXW4KyU17k,13205
25
25
  sxs/utilities/dicts.py,sha256=CCpm3upG_9SRj9gjawukSUfaJ5asF-XRG2ausEXhYyg,695
26
26
  sxs/utilities/downloads.py,sha256=iBceWfahHKxslUuI3p2-jRDoqGhP7q2A-La9g6XtMGg,4488
27
27
  sxs/utilities/files.py,sha256=l7SNOg0ikgqXV3bmPJdXZQMQ_XPGXVUsIJIOjDVp3Mg,4517
28
28
  sxs/utilities/formats.py,sha256=EekLcSi-fhFdkPT7R9h10d9_0gZH4EomH5-RVQp-sg8,3867
29
- sxs/utilities/inspire.py,sha256=kDjY-UFJT-VTS3yJOT8fT6LJG-pRrX9TK8nv3RZqrbo,8431
29
+ sxs/utilities/inspire.py,sha256=5F4KJ2D9qaEArl7dlhMv-K3Dym5S5oQI5RTwZXKhXRw,5298
30
30
  sxs/utilities/monotonicity.py,sha256=YVwj3Tjew8dkpJJ9TReyuISD2ul5HJfkEJgCoiLru5Q,812
31
31
  sxs/utilities/pretty_print.py,sha256=ZDHR3uvkzQ3Whk_eIp3BB7Abh796nqyrVsQRa68zgGc,1473
32
32
  sxs/utilities/select.py,sha256=UgoEQIvkm8NBe6sD5O2gK0g9Pep-xvWoYQ3b7RxI-Ww,6727
@@ -78,7 +78,7 @@ sxs/zenodo/api/__init__.py,sha256=EM_eh4Q8R5E0vIfMhyIR1IYFfOBu6vA0UTasgX9gHys,21
78
78
  sxs/zenodo/api/deposit.py,sha256=J4RGvGjh0cEOrN4bBZWEDcPAhNscqB2fzLlvRZ5HTHM,36948
79
79
  sxs/zenodo/api/login.py,sha256=Yz0ytgi81_5BpDzhrS0WPMXlvU2qUaCK8yn8zxfEbko,18007
80
80
  sxs/zenodo/api/records.py,sha256=nKkhoHZ95CTztHF9Zzaug5p7IiUCJG4Em1i-l-WqH6U,3689
81
- sxs-2024.0.2.dist-info/METADATA,sha256=uIlmdAKQsErr1V2TuvSZnjh_v1I78nP5Or0FfGQHPV8,9301
82
- sxs-2024.0.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
83
- sxs-2024.0.2.dist-info/licenses/LICENSE,sha256=ptVOd5m7LDM5ZF0x32cxb8c2Nd5NDmAhy6DX7xt_7VA,1080
84
- sxs-2024.0.2.dist-info/RECORD,,
81
+ sxs-2024.0.3.dist-info/METADATA,sha256=SfqRh4qE3Aa6DGh_MDuVXtaO6Fci0U6hVfC-XeCQsTE,9301
82
+ sxs-2024.0.3.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
83
+ sxs-2024.0.3.dist-info/licenses/LICENSE,sha256=ptVOd5m7LDM5ZF0x32cxb8c2Nd5NDmAhy6DX7xt_7VA,1080
84
+ sxs-2024.0.3.dist-info/RECORD,,
File without changes