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.
- {cmsdials-1.3.0 → cmsdials-1.5.0}/PKG-INFO +99 -2
- {cmsdials-1.3.0 → cmsdials-1.5.0}/README.md +97 -1
- cmsdials-1.5.0/cmsdials/clients/dataset_index/client.py +13 -0
- cmsdials-1.5.0/cmsdials/clients/dataset_index/models.py +30 -0
- cmsdials-1.5.0/cmsdials/clients/file_index/client.py +13 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/file_index/models.py +1 -0
- cmsdials-1.5.0/cmsdials/clients/h1d/client.py +13 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/h1d/models.py +1 -0
- cmsdials-1.5.0/cmsdials/clients/h2d/client.py +13 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/h2d/models.py +1 -0
- cmsdials-1.5.0/cmsdials/clients/lumisection/client.py +13 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/lumisection/models.py +1 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/mes/client.py +4 -0
- cmsdials-1.5.0/cmsdials/clients/ml_bad_lumisection/client.py +29 -0
- cmsdials-1.5.0/cmsdials/clients/ml_bad_lumisection/models.py +38 -0
- cmsdials-1.5.0/cmsdials/clients/ml_models_index/client.py +13 -0
- cmsdials-1.5.0/cmsdials/clients/ml_models_index/models.py +30 -0
- cmsdials-1.5.0/cmsdials/clients/oms_proxy/__init__.py +0 -0
- cmsdials-1.5.0/cmsdials/clients/run/__init__.py +0 -0
- cmsdials-1.5.0/cmsdials/clients/run/client.py +13 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/run/models.py +1 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/cmsdials.py +6 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/filters.py +6 -0
- cmsdials-1.5.0/cmsdials/utils/__init__.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/utils/api_client.py +85 -13
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/utils/base_model.py +9 -1
- {cmsdials-1.3.0 → cmsdials-1.5.0}/pyproject.toml +2 -1
- cmsdials-1.3.0/cmsdials/clients/file_index/client.py +0 -27
- cmsdials-1.3.0/cmsdials/clients/h1d/client.py +0 -27
- cmsdials-1.3.0/cmsdials/clients/h2d/client.py +0 -27
- cmsdials-1.3.0/cmsdials/clients/lumisection/client.py +0 -27
- cmsdials-1.3.0/cmsdials/clients/run/client.py +0 -27
- {cmsdials-1.3.0 → cmsdials-1.5.0}/LICENSE +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/__init__.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/__init__.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/_base.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/bearer.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/client.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/exceptions.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/models.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/auth/secret_key.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/__init__.py +0 -0
- {cmsdials-1.3.0/cmsdials/clients/file_index → cmsdials-1.5.0/cmsdials/clients/dataset_index}/__init__.py +0 -0
- {cmsdials-1.3.0/cmsdials/clients/h1d → cmsdials-1.5.0/cmsdials/clients/file_index}/__init__.py +0 -0
- {cmsdials-1.3.0/cmsdials/clients/h2d → cmsdials-1.5.0/cmsdials/clients/h1d}/__init__.py +0 -0
- {cmsdials-1.3.0/cmsdials/clients/lumisection → cmsdials-1.5.0/cmsdials/clients/h2d}/__init__.py +0 -0
- {cmsdials-1.3.0/cmsdials/clients/mes → cmsdials-1.5.0/cmsdials/clients/lumisection}/__init__.py +0 -0
- {cmsdials-1.3.0/cmsdials/clients/oms_proxy → cmsdials-1.5.0/cmsdials/clients/mes}/__init__.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/mes/models.py +0 -0
- {cmsdials-1.3.0/cmsdials/clients/run → cmsdials-1.5.0/cmsdials/clients/ml_bad_lumisection}/__init__.py +0 -0
- {cmsdials-1.3.0/cmsdials/utils → cmsdials-1.5.0/cmsdials/clients/ml_models_index}/__init__.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/oms_proxy/client.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/clients/oms_proxy/models.py +0 -0
- {cmsdials-1.3.0 → cmsdials-1.5.0}/cmsdials/utils/_json.py +0 -0
- {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
|
+
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
|
|
@@ -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
|
|
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,
|
|
69
|
-
endpoint_url = self.api_url + self.lookup_url +
|
|
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 =
|
|
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 =
|
|
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(
|
|
103
|
-
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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=
|
|
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 {
|
|
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
|
+
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cmsdials-1.3.0/cmsdials/clients/h1d → cmsdials-1.5.0/cmsdials/clients/file_index}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{cmsdials-1.3.0/cmsdials/clients/lumisection → cmsdials-1.5.0/cmsdials/clients/h2d}/__init__.py
RENAMED
|
File without changes
|
{cmsdials-1.3.0/cmsdials/clients/mes → cmsdials-1.5.0/cmsdials/clients/lumisection}/__init__.py
RENAMED
|
File without changes
|
{cmsdials-1.3.0/cmsdials/clients/oms_proxy → cmsdials-1.5.0/cmsdials/clients/mes}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cmsdials-1.3.0/cmsdials/utils → cmsdials-1.5.0/cmsdials/clients/ml_models_index}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|