cmsdials 1.3.0__tar.gz → 1.5.0__tar.gz

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.
Files changed (55) hide show
  1. {cmsdials-1.3.0 → cmsdials-1.5.0}/PKG-INFO +99 -2
  2. {cmsdials-1.3.0 → cmsdials-1.5.0}/README.md +97 -1
  3. cmsdials-1.5.0/cmsdials/clients/dataset_index/client.py +13 -0
  4. cmsdials-1.5.0/cmsdials/clients/dataset_index/models.py +30 -0
  5. cmsdials-1.5.0/cmsdials/clients/file_index/client.py +13 -0
  6. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/file_index/models.py +1 -0
  7. cmsdials-1.5.0/cmsdials/clients/h1d/client.py +13 -0
  8. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/h1d/models.py +1 -0
  9. cmsdials-1.5.0/cmsdials/clients/h2d/client.py +13 -0
  10. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/h2d/models.py +1 -0
  11. cmsdials-1.5.0/cmsdials/clients/lumisection/client.py +13 -0
  12. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/lumisection/models.py +1 -0
  13. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/mes/client.py +4 -0
  14. cmsdials-1.5.0/cmsdials/clients/ml_bad_lumisection/client.py +29 -0
  15. cmsdials-1.5.0/cmsdials/clients/ml_bad_lumisection/models.py +38 -0
  16. cmsdials-1.5.0/cmsdials/clients/ml_models_index/client.py +13 -0
  17. cmsdials-1.5.0/cmsdials/clients/ml_models_index/models.py +30 -0
  18. cmsdials-1.5.0/cmsdials/clients/oms_proxy/__init__.py +0 -0
  19. cmsdials-1.5.0/cmsdials/clients/run/__init__.py +0 -0
  20. cmsdials-1.5.0/cmsdials/clients/run/client.py +13 -0
  21. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/run/models.py +1 -0
  22. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/cmsdials.py +6 -0
  23. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/filters.py +6 -0
  24. cmsdials-1.5.0/cmsdials/utils/__init__.py +0 -0
  25. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/utils/api_client.py +85 -13
  26. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/utils/base_model.py +9 -1
  27. {cmsdials-1.3.0 → cmsdials-1.5.0}/pyproject.toml +2 -1
  28. cmsdials-1.3.0/cmsdials/clients/file_index/client.py +0 -27
  29. cmsdials-1.3.0/cmsdials/clients/h1d/client.py +0 -27
  30. cmsdials-1.3.0/cmsdials/clients/h2d/client.py +0 -27
  31. cmsdials-1.3.0/cmsdials/clients/lumisection/client.py +0 -27
  32. cmsdials-1.3.0/cmsdials/clients/run/client.py +0 -27
  33. {cmsdials-1.3.0 → cmsdials-1.5.0}/LICENSE +0 -0
  34. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/__init__.py +0 -0
  35. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/__init__.py +0 -0
  36. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/_base.py +0 -0
  37. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/bearer.py +0 -0
  38. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/client.py +0 -0
  39. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/exceptions.py +0 -0
  40. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/models.py +0 -0
  41. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/secret_key.py +0 -0
  42. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/__init__.py +0 -0
  43. {cmsdials-1.3.0/cmsdials/clients/file_index → cmsdials-1.5.0/cmsdials/clients/dataset_index}/__init__.py +0 -0
  44. {cmsdials-1.3.0/cmsdials/clients/h1d → cmsdials-1.5.0/cmsdials/clients/file_index}/__init__.py +0 -0
  45. {cmsdials-1.3.0/cmsdials/clients/h2d → cmsdials-1.5.0/cmsdials/clients/h1d}/__init__.py +0 -0
  46. {cmsdials-1.3.0/cmsdials/clients/lumisection → cmsdials-1.5.0/cmsdials/clients/h2d}/__init__.py +0 -0
  47. {cmsdials-1.3.0/cmsdials/clients/mes → cmsdials-1.5.0/cmsdials/clients/lumisection}/__init__.py +0 -0
  48. {cmsdials-1.3.0/cmsdials/clients/oms_proxy → cmsdials-1.5.0/cmsdials/clients/mes}/__init__.py +0 -0
  49. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/mes/models.py +0 -0
  50. {cmsdials-1.3.0/cmsdials/clients/run → cmsdials-1.5.0/cmsdials/clients/ml_bad_lumisection}/__init__.py +0 -0
  51. {cmsdials-1.3.0/cmsdials/utils → cmsdials-1.5.0/cmsdials/clients/ml_models_index}/__init__.py +0 -0
  52. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/oms_proxy/client.py +0 -0
  53. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/oms_proxy/models.py +0 -0
  54. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/utils/_json.py +0 -0
  55. {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/utils/logger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cmsdials
3
- Version: 1.3.0
3
+ Version: 1.5.0
4
4
  Summary: The Python api client interface to DIALS service
5
5
  Home-page: https://github.com/cms-DQM/dials-py
6
6
  Author: Gabriel Moreira
@@ -22,6 +22,7 @@ Requires-Dist: pydantic (>=1,<2)
22
22
  Requires-Dist: requests (>=2.31.0,<3.0.0)
23
23
  Requires-Dist: tqdm (>=4.66.1) ; extra == "tqdm"
24
24
  Requires-Dist: typing-extensions (>=3.6.6,<4.6.0)
25
+ Requires-Dist: urllib3 (>=2.2.3,<3.0.0)
25
26
  Project-URL: Repository, https://github.com/cms-DQM/dials-py
26
27
  Description-Content-Type: text/markdown
27
28
 
@@ -107,11 +108,16 @@ This package interacts with DIALS api endpoints using underlying classes in `Dia
107
108
  ### Retrieving a specific object using `get`
108
109
 
109
110
  ```python
111
+ dials.dataset_index.get(dataset_id=14677060)
110
112
  dials.file_index.get(dataset_id=14677060, file_id=3393809397)
111
113
  dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=1)
112
114
  dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=96)
113
115
  dials.lumi.get(dataset_id=14677060, run_number=367112, ls_number=10)
114
116
  dials.run.get(dataset_id=14677060, run_number=367112)
117
+
118
+ # jetmet worskpace
119
+ dials.ml_models_index(model_id=1)
120
+ dials.ml_bad_lumisection(model_id=19, dataset_id=15102369, run_number=386951, ls_number=36)
115
121
  ```
116
122
 
117
123
  ### Retrieving a list of objects per page using `list`
@@ -119,11 +125,14 @@ dials.run.get(dataset_id=14677060, run_number=367112)
119
125
  It is possible to get a list of entries from those endpoint using the `list` and `list_all` methods, the `list` method will fetch only one page and the `list_all` will fetch all available pages:
120
126
 
121
127
  ```python
128
+ dials.dataset_index.list()
122
129
  dials.file_index.list()
123
130
  dials.h1d.list()
124
131
  dials.h2d.list()
125
132
  dials.lumi.list()
126
133
  dials.run.list()
134
+ dials.ml_models_index.list()
135
+ dials.ml_bad_lumisection.list()
127
136
  ```
128
137
 
129
138
  ### Retrieving all available pages of a list of objects using `list_all`
@@ -131,11 +140,14 @@ dials.run.list()
131
140
  Note: Keep in mind that running `list_all` without any filter can take too much time, since you will be retrieving all rows in the database.
132
141
 
133
142
  ```python
143
+ dials.dataset_index.list_all()
134
144
  dials.file_index.list_all()
135
145
  dials.h1d.list_all()
136
146
  dials.h2d.list_all()
137
147
  dials.lumi.list_all()
138
148
  dials.run.list_all()
149
+ dials.ml_models_index.list_all()
150
+ dials.ml_bad_lumisection.list_all()
139
151
  ```
140
152
 
141
153
  If you don't need all available pages but just a subset of then, it is possible to specify a `max_pages` integer parameter:
@@ -154,9 +166,12 @@ from cmsdials.filters import (
154
166
  LumisectionHistogram1DFilters,
155
167
  LumisectionHistogram2DFilters,
156
168
  LumisectionFilters,
157
- RunFilters
169
+ RunFilters,
170
+ MLBadLumisectionFilters
158
171
  )
159
172
 
173
+ dials.dataset_index.list_all(DatasetIndexFilters(page_size=500))
174
+
160
175
  dials.file_index.list(FileIndexFilters(dataset__regex="2024B"))
161
176
 
162
177
  dials.h1d.list(LumisectionHistogram1DFilters(me="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"))
@@ -166,6 +181,19 @@ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number
166
181
  dials.lumi.list_all(LumisectionFilters(run_number=360392), max_pages=5)
167
182
 
168
183
  dials.run.list_all(RunFilters(run_number__gte=360392, run_number__lte=365000), max_pages=5)
184
+
185
+ # jetmet workspace
186
+ dials.ml_models_index.list_all(MLModelsIndexFilters(active=True))
187
+
188
+ # jetmet workspace
189
+ dials.ml_bad_lumis.list_all(
190
+ MLBadLumisectionFilters(
191
+ page_size=500,
192
+ model_id__in=[20,19],
193
+ dataset_id__in=[15042670],
194
+ run_number__in=[385801,385799,385764]
195
+ )
196
+ )
169
197
  ```
170
198
 
171
199
  ### Dials MEs
@@ -200,6 +228,75 @@ Progress: 100%|█████████████████████
200
228
 
201
229
  The total attribute of the bar is dynamically updated while fetching the pages.
202
230
 
231
+ ## Retrying
232
+
233
+ In case of an unstable connection, DNS failures or service overload it is possible to configure any `get`, `list` and `list_all` to retry the underlying requests using native `urllib3` retry class, for example:
234
+
235
+ ```python
236
+ from urllib3.util import Retry
237
+
238
+ data = dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=1, retries=Retry(total=3, backoff_factor=0.1))
239
+ data = dials.h1d.list(retries=Retry(total=3, backoff_factor=0.1))
240
+ data = dials.h1d.list_all(LumisectionHistogram1DFilters(), max_pages=5, retries=Retry(total=5, backoff_factor=0.1))
241
+ ```
242
+
243
+ ## Resuming
244
+
245
+ When listing and endpoint for a long time, you may loose connection or the server can potentially return an error. By specifying `keep_failed` and using `resume_from` you can resume from an older response object, for example:
246
+
247
+ ```python
248
+ from cmsdials.auth.client import AuthClient
249
+ from cmsdials.auth.bearer import Credentials
250
+ from cmsdials import Dials
251
+ from cmsdials.filters import LumisectionHistogram2DFilters
252
+
253
+ auth = AuthClient()
254
+ creds = Credentials.from_creds_file()
255
+ dials = Dials(creds, workspace="tracker")
256
+
257
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), keep_failed=True) # Code may broke inside this routine
258
+ print(len(data.results)) # 100
259
+ print(data.exc_type)
260
+ print(data.exc_formatted)
261
+
262
+ # After failing, run this again
263
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), keep_failed=True, resume_from=data) # Resume from failed object
264
+ print(len(data.results)) # 200
265
+ ```
266
+
267
+ You may find it useful to resume from a partial response, i.e,
268
+
269
+ ```python
270
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), max_pages=10, keep_failed=True) # Code may not break, however will fetch only 100 elements
271
+ print(len(data.results)) # 100
272
+
273
+ # After fetching first 100, fetch next 100
274
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), max_pages=10, keep_failed=True, resume_from=data) # Resume from partial object
275
+ print(len(data.results)) # 200
276
+ ```
277
+
278
+ ## Fetching ML certification json and ML golden-like json
279
+
280
+ The following examples are testable in the `jetmet` workspace:
281
+
282
+ ```python
283
+ dials.ml_bad_lumis.cert_json(
284
+ model_id__in=[20,19],
285
+ dataset_id__in=[15042670],
286
+ run_number__in=[385801,385799,385764]
287
+ )
288
+
289
+ dials.ml_bad_lumis.golden_json(
290
+ model_id__in=[20,19],
291
+ dataset_id__in=[15042670],
292
+ run_number__in=[385801,385799,385764]
293
+ )
294
+ ```
295
+
296
+ You may need to query the `ml_models_index` client to fetch the models ids you are interested and the `dataset-index` client to fetch the datasets ids. Take a look in the live documentation to check all possible filters.
297
+
298
+ Attention: Those endpoints doesn't return a Pydantic model, instead they are returning a plain json response. Consequently, the method `to_pandas` doesn't work on them.
299
+
203
300
  ## Usage with local DIALS
204
301
 
205
302
  All classes that interface the DIALS service inherits the class `BaseAPIClient` which propagate the `base_url`, `route` and `version` attributes with production values. In order to use dials-py with a local version of DIALS it is possible to overwrite those attributes when instantiating the `AuthClient` and the `Dials` client, for example:
@@ -80,11 +80,16 @@ This package interacts with DIALS api endpoints using underlying classes in `Dia
80
80
  ### Retrieving a specific object using `get`
81
81
 
82
82
  ```python
83
+ dials.dataset_index.get(dataset_id=14677060)
83
84
  dials.file_index.get(dataset_id=14677060, file_id=3393809397)
84
85
  dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=1)
85
86
  dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=96)
86
87
  dials.lumi.get(dataset_id=14677060, run_number=367112, ls_number=10)
87
88
  dials.run.get(dataset_id=14677060, run_number=367112)
89
+
90
+ # jetmet worskpace
91
+ dials.ml_models_index(model_id=1)
92
+ dials.ml_bad_lumisection(model_id=19, dataset_id=15102369, run_number=386951, ls_number=36)
88
93
  ```
89
94
 
90
95
  ### Retrieving a list of objects per page using `list`
@@ -92,11 +97,14 @@ dials.run.get(dataset_id=14677060, run_number=367112)
92
97
  It is possible to get a list of entries from those endpoint using the `list` and `list_all` methods, the `list` method will fetch only one page and the `list_all` will fetch all available pages:
93
98
 
94
99
  ```python
100
+ dials.dataset_index.list()
95
101
  dials.file_index.list()
96
102
  dials.h1d.list()
97
103
  dials.h2d.list()
98
104
  dials.lumi.list()
99
105
  dials.run.list()
106
+ dials.ml_models_index.list()
107
+ dials.ml_bad_lumisection.list()
100
108
  ```
101
109
 
102
110
  ### Retrieving all available pages of a list of objects using `list_all`
@@ -104,11 +112,14 @@ dials.run.list()
104
112
  Note: Keep in mind that running `list_all` without any filter can take too much time, since you will be retrieving all rows in the database.
105
113
 
106
114
  ```python
115
+ dials.dataset_index.list_all()
107
116
  dials.file_index.list_all()
108
117
  dials.h1d.list_all()
109
118
  dials.h2d.list_all()
110
119
  dials.lumi.list_all()
111
120
  dials.run.list_all()
121
+ dials.ml_models_index.list_all()
122
+ dials.ml_bad_lumisection.list_all()
112
123
  ```
113
124
 
114
125
  If you don't need all available pages but just a subset of then, it is possible to specify a `max_pages` integer parameter:
@@ -127,9 +138,12 @@ from cmsdials.filters import (
127
138
  LumisectionHistogram1DFilters,
128
139
  LumisectionHistogram2DFilters,
129
140
  LumisectionFilters,
130
- RunFilters
141
+ RunFilters,
142
+ MLBadLumisectionFilters
131
143
  )
132
144
 
145
+ dials.dataset_index.list_all(DatasetIndexFilters(page_size=500))
146
+
133
147
  dials.file_index.list(FileIndexFilters(dataset__regex="2024B"))
134
148
 
135
149
  dials.h1d.list(LumisectionHistogram1DFilters(me="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"))
@@ -139,6 +153,19 @@ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number
139
153
  dials.lumi.list_all(LumisectionFilters(run_number=360392), max_pages=5)
140
154
 
141
155
  dials.run.list_all(RunFilters(run_number__gte=360392, run_number__lte=365000), max_pages=5)
156
+
157
+ # jetmet workspace
158
+ dials.ml_models_index.list_all(MLModelsIndexFilters(active=True))
159
+
160
+ # jetmet workspace
161
+ dials.ml_bad_lumis.list_all(
162
+ MLBadLumisectionFilters(
163
+ page_size=500,
164
+ model_id__in=[20,19],
165
+ dataset_id__in=[15042670],
166
+ run_number__in=[385801,385799,385764]
167
+ )
168
+ )
142
169
  ```
143
170
 
144
171
  ### Dials MEs
@@ -173,6 +200,75 @@ Progress: 100%|█████████████████████
173
200
 
174
201
  The total attribute of the bar is dynamically updated while fetching the pages.
175
202
 
203
+ ## Retrying
204
+
205
+ In case of an unstable connection, DNS failures or service overload it is possible to configure any `get`, `list` and `list_all` to retry the underlying requests using native `urllib3` retry class, for example:
206
+
207
+ ```python
208
+ from urllib3.util import Retry
209
+
210
+ data = dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=1, retries=Retry(total=3, backoff_factor=0.1))
211
+ data = dials.h1d.list(retries=Retry(total=3, backoff_factor=0.1))
212
+ data = dials.h1d.list_all(LumisectionHistogram1DFilters(), max_pages=5, retries=Retry(total=5, backoff_factor=0.1))
213
+ ```
214
+
215
+ ## Resuming
216
+
217
+ When listing and endpoint for a long time, you may loose connection or the server can potentially return an error. By specifying `keep_failed` and using `resume_from` you can resume from an older response object, for example:
218
+
219
+ ```python
220
+ from cmsdials.auth.client import AuthClient
221
+ from cmsdials.auth.bearer import Credentials
222
+ from cmsdials import Dials
223
+ from cmsdials.filters import LumisectionHistogram2DFilters
224
+
225
+ auth = AuthClient()
226
+ creds = Credentials.from_creds_file()
227
+ dials = Dials(creds, workspace="tracker")
228
+
229
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), keep_failed=True) # Code may broke inside this routine
230
+ print(len(data.results)) # 100
231
+ print(data.exc_type)
232
+ print(data.exc_formatted)
233
+
234
+ # After failing, run this again
235
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), keep_failed=True, resume_from=data) # Resume from failed object
236
+ print(len(data.results)) # 200
237
+ ```
238
+
239
+ You may find it useful to resume from a partial response, i.e,
240
+
241
+ ```python
242
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), max_pages=10, keep_failed=True) # Code may not break, however will fetch only 100 elements
243
+ print(len(data.results)) # 100
244
+
245
+ # After fetching first 100, fetch next 100
246
+ data = dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), max_pages=10, keep_failed=True, resume_from=data) # Resume from partial object
247
+ print(len(data.results)) # 200
248
+ ```
249
+
250
+ ## Fetching ML certification json and ML golden-like json
251
+
252
+ The following examples are testable in the `jetmet` workspace:
253
+
254
+ ```python
255
+ dials.ml_bad_lumis.cert_json(
256
+ model_id__in=[20,19],
257
+ dataset_id__in=[15042670],
258
+ run_number__in=[385801,385799,385764]
259
+ )
260
+
261
+ dials.ml_bad_lumis.golden_json(
262
+ model_id__in=[20,19],
263
+ dataset_id__in=[15042670],
264
+ run_number__in=[385801,385799,385764]
265
+ )
266
+ ```
267
+
268
+ You may need to query the `ml_models_index` client to fetch the models ids you are interested and the `dataset-index` client to fetch the datasets ids. Take a look in the live documentation to check all possible filters.
269
+
270
+ Attention: Those endpoints doesn't return a Pydantic model, instead they are returning a plain json response. Consequently, the method `to_pandas` doesn't work on them.
271
+
176
272
  ## Usage with local DIALS
177
273
 
178
274
  All classes that interface the DIALS service inherits the class `BaseAPIClient` which propagate the `base_url`, `route` and `version` attributes with production values. In order to use dials-py with a local version of DIALS it is possible to overwrite those attributes when instantiating the `AuthClient` and the `Dials` client, for example:
@@ -0,0 +1,13 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import DatasetIndex, DatasetIndexFilters, PaginatedDatasetIndexList
3
+
4
+
5
+ class DatasetIndexClient(BaseAuthorizedAPIClient):
6
+ data_model = DatasetIndex
7
+ pagination_model = PaginatedDatasetIndexList
8
+ filter_class = DatasetIndexFilters
9
+ lookup_url = "dataset-index/"
10
+
11
+ def get(self, dataset_id: int, file_id: int, **kwargs):
12
+ edp = f"{dataset_id}/{file_id}/"
13
+ return super().get(edp, **kwargs)
@@ -0,0 +1,30 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
4
+ from pydantic import AnyUrl, BaseModel, Field
5
+
6
+ from ...utils.base_model import OBaseModel, PaginatedBaseModel
7
+
8
+
9
+ class DatasetIndex(BaseModel):
10
+ dataset_id: int
11
+ dataset: str = Field(..., max_length=255)
12
+ era: str = Field(..., max_length=255)
13
+ data_tier: str = Field(..., max_length=255)
14
+ primary_ds_name: str = Field(..., max_length=255)
15
+ processed_ds_name: str = Field(..., max_length=255)
16
+ processing_version: int
17
+ last_modification_date: datetime
18
+
19
+
20
+ class PaginatedDatasetIndexList(PaginatedBaseModel):
21
+ next: Optional[AnyUrl]
22
+ previous: Optional[AnyUrl]
23
+ results: list[DatasetIndex]
24
+
25
+
26
+ class DatasetIndexFilters(OBaseModel):
27
+ next_token: Optional[str] = None
28
+ page_size: Optional[int] = None
29
+ dataset: Optional[str] = None
30
+ dataset__regex: Optional[str] = None
@@ -0,0 +1,13 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import FileIndex, FileIndexFilters, PaginatedFileIndexList
3
+
4
+
5
+ class FileIndexClient(BaseAuthorizedAPIClient):
6
+ data_model = FileIndex
7
+ pagination_model = PaginatedFileIndexList
8
+ filter_class = FileIndexFilters
9
+ lookup_url = "file-index/"
10
+
11
+ def get(self, dataset_id: int, file_id: int, **kwargs):
12
+ edp = f"{dataset_id}/{file_id}/"
13
+ return super().get(edp, **kwargs)
@@ -26,6 +26,7 @@ class PaginatedFileIndexList(PaginatedBaseModel):
26
26
 
27
27
  class FileIndexFilters(OBaseModel):
28
28
  next_token: Optional[str] = None
29
+ page_size: Optional[int] = None
29
30
  dataset_id: Optional[int] = None
30
31
  logical_file_name: Optional[str] = None
31
32
  logical_file_name__regex: Optional[str] = None
@@ -0,0 +1,13 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import LumisectionHistogram1D, LumisectionHistogram1DFilters, PaginatedLumisectionHistogram1DList
3
+
4
+
5
+ class LumisectionHistogram1DClient(BaseAuthorizedAPIClient):
6
+ data_model = LumisectionHistogram1D
7
+ pagination_model = PaginatedLumisectionHistogram1DList
8
+ filter_class = LumisectionHistogram1DFilters
9
+ lookup_url = "th1/"
10
+
11
+ def get(self, dataset_id: int, run_number: int, ls_number: int, me_id: int, **kwargs):
12
+ edp = f"{dataset_id}/{run_number}/{ls_number}/{me_id}/"
13
+ return super().get(edp, **kwargs)
@@ -28,6 +28,7 @@ class PaginatedLumisectionHistogram1DList(PaginatedBaseModel):
28
28
 
29
29
  class LumisectionHistogram1DFilters(OBaseModel):
30
30
  next_token: Optional[str] = None
31
+ page_size: Optional[int] = None
31
32
  dataset_id: Optional[int] = None
32
33
  file_id: Optional[int] = None
33
34
  run_number: Optional[int] = None
@@ -0,0 +1,13 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import LumisectionHistogram2D, LumisectionHistogram2DFilters, PaginatedLumisectionHistogram2DList
3
+
4
+
5
+ class LumisectionHistogram2DClient(BaseAuthorizedAPIClient):
6
+ data_model = LumisectionHistogram2D
7
+ pagination_model = PaginatedLumisectionHistogram2DList
8
+ filter_class = LumisectionHistogram2DFilters
9
+ lookup_url = "th2/"
10
+
11
+ def get(self, dataset_id: int, run_number: int, ls_number: int, me_id: int, **kwargs):
12
+ edp = f"{dataset_id}/{run_number}/{ls_number}/{me_id}/"
13
+ return super().get(edp, **kwargs)
@@ -31,6 +31,7 @@ class PaginatedLumisectionHistogram2DList(PaginatedBaseModel):
31
31
 
32
32
  class LumisectionHistogram2DFilters(OBaseModel):
33
33
  next_token: Optional[str] = None
34
+ page_size: Optional[int] = None
34
35
  dataset_id: Optional[int] = None
35
36
  file_id: Optional[int] = None
36
37
  run_number: Optional[int] = None
@@ -0,0 +1,13 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import Lumisection, LumisectionFilters, PaginatedLumisectionList
3
+
4
+
5
+ class LumisectionClient(BaseAuthorizedAPIClient):
6
+ data_model = Lumisection
7
+ pagination_model = PaginatedLumisectionList
8
+ filter_class = LumisectionFilters
9
+ lookup_url = "lumisection/"
10
+
11
+ def get(self, dataset_id: int, run_number: int, ls_number: int, **kwargs):
12
+ edp = f"{dataset_id}/{run_number}/{ls_number}/"
13
+ return super().get(edp, **kwargs)
@@ -22,6 +22,7 @@ class PaginatedLumisectionList(PaginatedBaseModel):
22
22
 
23
23
  class LumisectionFilters(OBaseModel):
24
24
  next_token: Optional[str] = None
25
+ page_size: Optional[int] = None
25
26
  dataset_id: Optional[int] = None
26
27
  run_number: Optional[int] = None
27
28
  run_number__lte: Optional[int] = None
@@ -6,3 +6,7 @@ class MonitoringElementClient(BaseAuthorizedAPIClient):
6
6
  data_model = MonitoringElement
7
7
  filter_class = MEFilters
8
8
  lookup_url = "mes/"
9
+
10
+ def get(self, id: int, **kwargs): # noqa: A002
11
+ edp = f"{id}/"
12
+ return super().get(edp, **kwargs)
@@ -0,0 +1,29 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import MLBadLumisection, MLBadLumisectionFilters, PaginatedMLBadLumisectionList
3
+
4
+
5
+ class MLBadLumisectionClient(BaseAuthorizedAPIClient):
6
+ data_model = MLBadLumisection
7
+ pagination_model = PaginatedMLBadLumisectionList
8
+ filter_class = MLBadLumisectionFilters
9
+ lookup_url = "ml-bad-lumisection/"
10
+
11
+ def get(self, model_id: int, dataset_id: int, run_number: int, ls_number: int, me_id: int, **kwargs):
12
+ edp = f"{model_id}/{dataset_id}/{run_number}/{ls_number}/{me_id}/"
13
+ return super().get(edp, **kwargs)
14
+
15
+ def cert_json(self, model_id__in: list[int], dataset_id__in: list[int], run_number__in: list[int], **kwargs):
16
+ edp = "cert-json/"
17
+ midin = ",".join(str(v) for v in model_id__in)
18
+ didin = ",".join(str(v) for v in dataset_id__in)
19
+ ridin = ",".join(str(v) for v in run_number__in)
20
+ params = {"model_id__in": midin, "dataset_id__in": didin, "run_number__in": ridin}
21
+ return super().get(edp, params=params, return_raw_json=True, **kwargs)
22
+
23
+ def golden_json(self, model_id__in: list[int], dataset_id__in: list[int], run_number__in: list[int], **kwargs):
24
+ edp = "golden-json/"
25
+ midin = ",".join(str(v) for v in model_id__in)
26
+ didin = ",".join(str(v) for v in dataset_id__in)
27
+ ridin = ",".join(str(v) for v in run_number__in)
28
+ params = {"model_id__in": midin, "dataset_id__in": didin, "run_number__in": ridin}
29
+ return super().get(edp, params=params, return_raw_json=True, **kwargs)
@@ -0,0 +1,38 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import AnyUrl, BaseModel
4
+
5
+ from ...utils.base_model import OBaseModel, PaginatedBaseModel
6
+
7
+
8
+ class MLBadLumisection(BaseModel):
9
+ model_id: int
10
+ dataset_id: int
11
+ file_id: int
12
+ run_number: int
13
+ ls_number: int
14
+ me_id: int
15
+ mse: float
16
+
17
+
18
+ class PaginatedMLBadLumisectionList(PaginatedBaseModel):
19
+ next: Optional[AnyUrl]
20
+ previous: Optional[AnyUrl]
21
+ results: list[MLBadLumisection]
22
+
23
+
24
+ class MLBadLumisectionFilters(OBaseModel):
25
+ next_token: Optional[str] = None
26
+ page_size: Optional[int] = None
27
+ model_id: Optional[int] = None
28
+ model_id__in: Optional[list[int]] = None
29
+ dataset_id: Optional[int] = None
30
+ dataset_id__in: Optional[list[int]] = None
31
+ dataset: Optional[str] = None
32
+ dataset__regex: Optional[str] = None
33
+ me_id: Optional[int] = None
34
+ me: Optional[str] = None
35
+ me__regex: Optional[str] = None
36
+ run_number: Optional[int] = None
37
+ run_number__in: Optional[list[int]] = None
38
+ ls_number: Optional[int] = None
@@ -0,0 +1,13 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import MLModelsIndex, MLModelsIndexFilters, PaginatedMLModelsIndexList
3
+
4
+
5
+ class MLModelsIndexClient(BaseAuthorizedAPIClient):
6
+ data_model = MLModelsIndex
7
+ pagination_model = PaginatedMLModelsIndexList
8
+ filter_class = MLModelsIndexFilters
9
+ lookup_url = "ml-models-index/"
10
+
11
+ def get(self, model_id: int, **kwargs):
12
+ edp = f"{model_id}/"
13
+ return super().get(edp, **kwargs)
@@ -0,0 +1,30 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import AnyUrl, BaseModel
4
+
5
+ from ...utils.base_model import OBaseModel, PaginatedBaseModel
6
+
7
+
8
+ class MLModelsIndex(BaseModel):
9
+ model_id: int
10
+ filename: str
11
+ target_me: str
12
+ active: bool
13
+
14
+
15
+ class PaginatedMLModelsIndexList(PaginatedBaseModel):
16
+ next: Optional[AnyUrl]
17
+ previous: Optional[AnyUrl]
18
+ results: list[MLModelsIndex]
19
+
20
+
21
+ class MLModelsIndexFilters(OBaseModel):
22
+ next_token: Optional[str] = None
23
+ page_size: Optional[int] = None
24
+ model_id: Optional[int] = None
25
+ model_id__in: Optional[list[int]] = None
26
+ filename: Optional[str] = None
27
+ filename__regex: Optional[str] = None
28
+ target_me: Optional[str] = None
29
+ target_me__regex: Optional[str] = None
30
+ active: Optional[bool] = None
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ from ...utils.api_client import BaseAuthorizedAPIClient
2
+ from .models import PaginatedRunList, Run, RunFilters
3
+
4
+
5
+ class RunClient(BaseAuthorizedAPIClient):
6
+ data_model = Run
7
+ pagination_model = PaginatedRunList
8
+ filter_class = RunFilters
9
+ lookup_url = "run/"
10
+
11
+ def get(self, dataset_id: int, run_number: int, **kwargs):
12
+ edp = f"{dataset_id}/{run_number}/"
13
+ return super().get(edp, **kwargs)
@@ -20,6 +20,7 @@ class PaginatedRunList(PaginatedBaseModel):
20
20
 
21
21
  class RunFilters(OBaseModel):
22
22
  next_token: Optional[str] = None
23
+ page_size: Optional[int] = None
23
24
  dataset_id: Optional[int] = None
24
25
  run_number: Optional[int] = None
25
26
  run_number__lte: Optional[int] = None
@@ -1,17 +1,21 @@
1
1
  from typing import Optional
2
2
 
3
3
  from .auth._base import BaseCredentials
4
+ from .clients.dataset_index.client import DatasetIndexClient
4
5
  from .clients.file_index.client import FileIndexClient
5
6
  from .clients.h1d.client import LumisectionHistogram1DClient
6
7
  from .clients.h2d.client import LumisectionHistogram2DClient
7
8
  from .clients.lumisection.client import LumisectionClient
8
9
  from .clients.mes.client import MonitoringElementClient
10
+ from .clients.ml_bad_lumisection.client import MLBadLumisectionClient
11
+ from .clients.ml_models_index.client import MLModelsIndexClient
9
12
  from .clients.oms_proxy.client import OMSProxyClient
10
13
  from .clients.run.client import RunClient
11
14
 
12
15
 
13
16
  class Dials:
14
17
  def __init__(self, creds: BaseCredentials, workspace: Optional[str] = None, *args, **kwargs) -> None:
18
+ self.dataset_index = DatasetIndexClient(creds, workspace, *args, **kwargs)
15
19
  self.file_index = FileIndexClient(creds, workspace, *args, **kwargs)
16
20
  self.h1d = LumisectionHistogram1DClient(creds, workspace, *args, **kwargs)
17
21
  self.h2d = LumisectionHistogram2DClient(creds, workspace, *args, **kwargs)
@@ -19,3 +23,5 @@ class Dials:
19
23
  self.run = RunClient(creds, workspace, *args, **kwargs)
20
24
  self.mes = MonitoringElementClient(creds, workspace, *args, **kwargs)
21
25
  self.oms = OMSProxyClient(creds, *args, **kwargs)
26
+ self.ml_bad_lumis = MLBadLumisectionClient(creds, workspace, *args, **kwargs)
27
+ self.ml_models_index = MLModelsIndexClient(creds, workspace, *args, **kwargs)
@@ -1,19 +1,25 @@
1
+ from .clients.dataset_index.models import DatasetIndexFilters
1
2
  from .clients.file_index.models import FileIndexFilters
2
3
  from .clients.h1d.models import LumisectionHistogram1DFilters
3
4
  from .clients.h2d.models import LumisectionHistogram2DFilters
4
5
  from .clients.lumisection.models import LumisectionFilters
5
6
  from .clients.mes.models import MEFilters
7
+ from .clients.ml_bad_lumisection.models import MLBadLumisectionFilters
8
+ from .clients.ml_models_index.models import MLModelsIndexFilters
6
9
  from .clients.oms_proxy.models import OMSFilter, OMSPage
7
10
  from .clients.run.models import RunFilters
8
11
 
9
12
 
10
13
  __all__ = [
14
+ "DatasetIndexFilters",
11
15
  "FileIndexFilters",
12
16
  "LumisectionHistogram1DFilters",
13
17
  "LumisectionHistogram2DFilters",
14
18
  "LumisectionFilters",
15
19
  "RunFilters",
16
20
  "MEFilters",
21
+ "MLBadLumisectionFilters",
22
+ "MLModelsIndexFilters",
17
23
  "OMSFilter",
18
24
  "OMSPage",
19
25
  ]
File without changes
@@ -1,8 +1,11 @@
1
1
  from importlib import util as importlib_util
2
+ from traceback import format_exc
2
3
  from typing import Optional
3
4
  from urllib.parse import parse_qs, urlparse
5
+ from warnings import warn
4
6
 
5
- import requests
7
+ from requests import Response, Session
8
+ from requests.adapters import DEFAULT_RETRIES, HTTPAdapter
6
9
  from requests.exceptions import HTTPError
7
10
 
8
11
  from ..auth._base import BaseCredentials
@@ -35,6 +38,19 @@ class BaseAPIClient:
35
38
  return value + "/"
36
39
  return value
37
40
 
41
+ @classmethod
42
+ def _requests_get_retriable(cls, *args, retries=DEFAULT_RETRIES, **kwargs) -> Response:
43
+ """
44
+ requests.get() with an additional `retries` parameter.
45
+
46
+ Specify retries=<number of attempts - 1> for simple use cases.
47
+ For advanced usage, see https://docs.python-requests.org/en/latest/user/advanced/
48
+ """
49
+ with Session() as s:
50
+ s.mount(cls.PRODUCTION_BASE_URL, HTTPAdapter(max_retries=retries))
51
+ ret = s.get(*args, **kwargs)
52
+ return ret
53
+
38
54
  @property
39
55
  def api_url(self):
40
56
  return self.base_url + self.route + self.version
@@ -65,10 +81,16 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
65
81
  self.creds.before_request(base)
66
82
  return base
67
83
 
68
- def get(self, id: int): # noqa: A002
69
- endpoint_url = self.api_url + self.lookup_url + str(id) + "/"
84
+ def get(self, edp: str, retries=DEFAULT_RETRIES, params: Optional[dict] = None, return_raw_json: bool = False):
85
+ endpoint_url = self.api_url + self.lookup_url + edp
70
86
  headers = self._build_headers()
71
- response = requests.get(endpoint_url, headers=headers, timeout=self.default_timeout)
87
+ response = self._requests_get_retriable(
88
+ endpoint_url,
89
+ headers=headers,
90
+ params=params,
91
+ timeout=self.default_timeout,
92
+ retries=retries,
93
+ )
72
94
 
73
95
  try:
74
96
  response.raise_for_status()
@@ -77,13 +99,21 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
77
99
  raise err
78
100
 
79
101
  response = response.json()
102
+ if return_raw_json:
103
+ return response
80
104
  return self.data_model(**response)
81
105
 
82
- def list(self, filters=None):
106
+ def list(self, filters=None, retries=DEFAULT_RETRIES):
83
107
  filters = filters or self.filter_class()
84
108
  endpoint_url = self.api_url + self.lookup_url
85
109
  headers = self._build_headers()
86
- response = requests.get(endpoint_url, headers=headers, params=filters.cleandict(), timeout=self.default_timeout)
110
+ response = self._requests_get_retriable(
111
+ endpoint_url,
112
+ headers=headers,
113
+ params=filters.cleandict(),
114
+ timeout=self.default_timeout,
115
+ retries=retries,
116
+ )
87
117
 
88
118
  try:
89
119
  response.raise_for_status()
@@ -99,10 +129,30 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
99
129
 
100
130
  raise ValueError("pagination model is None and response is not a list.")
101
131
 
102
- def __list_sync(self, filters, max_pages: Optional[int] = None, enable_progress: bool = False):
103
- next_token = None
132
+ def __list_sync(
133
+ self,
134
+ filters,
135
+ max_pages: Optional[int] = None,
136
+ enable_progress: bool = False,
137
+ retries=DEFAULT_RETRIES,
138
+ keep_failed: bool = False,
139
+ resume_from=None,
140
+ ):
141
+ next_string: Optional[str] = None
104
142
  results = []
105
143
  is_last_page = False
144
+
145
+ if resume_from is not None:
146
+ results = resume_from.results
147
+ next_string = resume_from.next
148
+ if next_string is None and len(results):
149
+ warn(
150
+ "resume_from.next is None while resume_from.result is not empty, doing nothing.",
151
+ RuntimeWarning,
152
+ stacklevel=2,
153
+ )
154
+ is_last_page = True
155
+
106
156
  total_pages = 0
107
157
  use_tqdm = TQDM_INSTALLED and enable_progress
108
158
 
@@ -110,12 +160,34 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
110
160
  progress = tqdm(desc="Progress", total=1)
111
161
 
112
162
  while is_last_page is False:
163
+ next_token = parse_qs(urlparse(next_string).query).get("next_token") if next_string else None
113
164
  curr_filters = self.filter_class(**filters.dict())
114
165
  curr_filters.next_token = next_token
115
- response = self.list(curr_filters)
166
+ try:
167
+ response = self.list(curr_filters, retries=retries)
168
+ except Exception as e: # noqa: BLE001
169
+ if use_tqdm:
170
+ progress.close()
171
+
172
+ if not keep_failed:
173
+ raise e
174
+
175
+ exc_formatted = format_exc()
176
+ warn(
177
+ "HTTP request failed, returning partial results. Exception: " + exc_formatted,
178
+ RuntimeWarning,
179
+ stacklevel=2,
180
+ )
181
+ return self.pagination_model(
182
+ next=next_string,
183
+ previous=None,
184
+ results=results,
185
+ exc_type=e.__class__.__name__,
186
+ exc_formatted=exc_formatted,
187
+ )
116
188
  results.extend(response.results)
117
- is_last_page = response.next is None
118
- next_token = parse_qs(urlparse(response.next).query).get("next_token") if response.next else None
189
+ next_string = response.next
190
+ is_last_page = next_string is None
119
191
  total_pages += 1
120
192
  max_pages_reached = max_pages and total_pages >= max_pages
121
193
  if use_tqdm:
@@ -131,12 +203,12 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
131
203
  progress.close()
132
204
 
133
205
  return self.pagination_model(
134
- next=None,
206
+ next=next_string,
135
207
  previous=None,
136
208
  results=results, # No problem re-using last response count
137
209
  )
138
210
 
139
211
  def list_all(self, filters, max_pages: Optional[int] = None, **kwargs):
140
212
  if self.pagination_model is None:
141
- return self.list(filters)
213
+ return self.list(filters, retries=kwargs.get("retries", DEFAULT_RETRIES))
142
214
  return self.__list_sync(filters, max_pages, **kwargs)
@@ -1,4 +1,5 @@
1
1
  from importlib import util as importlib_util
2
+ from typing import Optional
2
3
 
3
4
  from pydantic import BaseModel
4
5
 
@@ -13,10 +14,17 @@ else:
13
14
 
14
15
  class OBaseModel(BaseModel):
15
16
  def cleandict(self):
16
- return {key: value for key, value in self.dict().items() if value is not None}
17
+ return {
18
+ key: ",".join(str(v) for v in value) if isinstance(value, (list, tuple)) else value
19
+ for key, value in self.dict().items()
20
+ if value is not None
21
+ }
17
22
 
18
23
 
19
24
  class PaginatedBaseModel(BaseModel):
25
+ exc_type: Optional[str] = None
26
+ exc_formatted: Optional[str] = None
27
+
20
28
  def to_pandas(self):
21
29
  if PANDAS_NOT_INSTALLED:
22
30
  raise RuntimeError(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cmsdials"
3
- version = "1.3.0"
3
+ version = "1.5.0"
4
4
  description = "The Python api client interface to DIALS service"
5
5
  authors = ["Gabriel Moreira <gabrielmscampos@gmail.com>"]
6
6
  readme = "README.md"
@@ -23,6 +23,7 @@ pydantic = "<2, >=1"
23
23
  typing-extensions = "<4.6.0, >=3.6.6"
24
24
  pandas = {version = ">=1.5.3", optional = true}
25
25
  tqdm = {version = ">=4.66.1", optional = true}
26
+ urllib3 = "^2.2.3"
26
27
 
27
28
  [tool.poetry.group.dev.dependencies]
28
29
  pre-commit = "^3.6.2"
@@ -1,27 +0,0 @@
1
- import requests
2
- from requests.exceptions import HTTPError
3
-
4
- from ...utils.api_client import BaseAuthorizedAPIClient
5
- from ...utils.logger import logger
6
- from .models import FileIndex, FileIndexFilters, PaginatedFileIndexList
7
-
8
-
9
- class FileIndexClient(BaseAuthorizedAPIClient):
10
- data_model = FileIndex
11
- pagination_model = PaginatedFileIndexList
12
- filter_class = FileIndexFilters
13
- lookup_url = "file-index/"
14
-
15
- def get(self, dataset_id: int, file_id: int):
16
- endpoint_url = f"{self.api_url}{self.lookup_url}{dataset_id}/{file_id}/"
17
- headers = self._build_headers()
18
- response = requests.get(endpoint_url, headers=headers, timeout=self.default_timeout)
19
-
20
- try:
21
- response.raise_for_status()
22
- except HTTPError as err:
23
- logger.info(f"Api raw response: {response.text}")
24
- raise err
25
-
26
- response = response.json()
27
- return self.data_model(**response)
@@ -1,27 +0,0 @@
1
- import requests
2
- from requests.exceptions import HTTPError
3
-
4
- from ...utils.api_client import BaseAuthorizedAPIClient
5
- from ...utils.logger import logger
6
- from .models import LumisectionHistogram1D, LumisectionHistogram1DFilters, PaginatedLumisectionHistogram1DList
7
-
8
-
9
- class LumisectionHistogram1DClient(BaseAuthorizedAPIClient):
10
- data_model = LumisectionHistogram1D
11
- pagination_model = PaginatedLumisectionHistogram1DList
12
- filter_class = LumisectionHistogram1DFilters
13
- lookup_url = "th1/"
14
-
15
- def get(self, dataset_id: int, run_number: int, ls_number: int, me_id: int):
16
- endpoint_url = f"{self.api_url}{self.lookup_url}{dataset_id}/{run_number}/{ls_number}/{me_id}/"
17
- headers = self._build_headers()
18
- response = requests.get(endpoint_url, headers=headers, timeout=self.default_timeout)
19
-
20
- try:
21
- response.raise_for_status()
22
- except HTTPError as err:
23
- logger.info(f"Api raw response: {response.text}")
24
- raise err
25
-
26
- response = response.json()
27
- return self.data_model(**response)
@@ -1,27 +0,0 @@
1
- import requests
2
- from requests.exceptions import HTTPError
3
-
4
- from ...utils.api_client import BaseAuthorizedAPIClient
5
- from ...utils.logger import logger
6
- from .models import LumisectionHistogram2D, LumisectionHistogram2DFilters, PaginatedLumisectionHistogram2DList
7
-
8
-
9
- class LumisectionHistogram2DClient(BaseAuthorizedAPIClient):
10
- data_model = LumisectionHistogram2D
11
- pagination_model = PaginatedLumisectionHistogram2DList
12
- filter_class = LumisectionHistogram2DFilters
13
- lookup_url = "th2/"
14
-
15
- def get(self, dataset_id: int, run_number: int, ls_number: int, me_id: int):
16
- endpoint_url = f"{self.api_url}{self.lookup_url}{dataset_id}/{run_number}/{ls_number}/{me_id}/"
17
- headers = self._build_headers()
18
- response = requests.get(endpoint_url, headers=headers, timeout=self.default_timeout)
19
-
20
- try:
21
- response.raise_for_status()
22
- except HTTPError as err:
23
- logger.info(f"Api raw response: {response.text}")
24
- raise err
25
-
26
- response = response.json()
27
- return self.data_model(**response)
@@ -1,27 +0,0 @@
1
- import requests
2
- from requests.exceptions import HTTPError
3
-
4
- from ...utils.api_client import BaseAuthorizedAPIClient
5
- from ...utils.logger import logger
6
- from .models import Lumisection, LumisectionFilters, PaginatedLumisectionList
7
-
8
-
9
- class LumisectionClient(BaseAuthorizedAPIClient):
10
- data_model = Lumisection
11
- pagination_model = PaginatedLumisectionList
12
- filter_class = LumisectionFilters
13
- lookup_url = "lumisection/"
14
-
15
- def get(self, dataset_id: int, run_number: int, ls_number: int):
16
- endpoint_url = f"{self.api_url}{self.lookup_url}{dataset_id}/{run_number}/{ls_number}/"
17
- headers = self._build_headers()
18
- response = requests.get(endpoint_url, headers=headers, timeout=self.default_timeout)
19
-
20
- try:
21
- response.raise_for_status()
22
- except HTTPError as err:
23
- logger.info(f"Api raw response: {response.text}")
24
- raise err
25
-
26
- response = response.json()
27
- return self.data_model(**response)
@@ -1,27 +0,0 @@
1
- import requests
2
- from requests.exceptions import HTTPError
3
-
4
- from ...utils.api_client import BaseAuthorizedAPIClient
5
- from ...utils.logger import logger
6
- from .models import PaginatedRunList, Run, RunFilters
7
-
8
-
9
- class RunClient(BaseAuthorizedAPIClient):
10
- data_model = Run
11
- pagination_model = PaginatedRunList
12
- filter_class = RunFilters
13
- lookup_url = "run/"
14
-
15
- def get(self, dataset_id: int, run_number: int):
16
- endpoint_url = f"{self.api_url}{self.lookup_url}{dataset_id}/{run_number}/"
17
- headers = self._build_headers()
18
- response = requests.get(endpoint_url, headers=headers, timeout=self.default_timeout)
19
-
20
- try:
21
- response.raise_for_status()
22
- except HTTPError as err:
23
- logger.info(f"Api raw response: {response.text}")
24
- raise err
25
-
26
- response = response.json()
27
- return self.data_model(**response)
File without changes
File without changes