cmsdials 0.4.0__tar.gz → 1.0.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 (42) hide show
  1. {cmsdials-0.4.0 → cmsdials-1.0.0}/PKG-INFO +16 -15
  2. {cmsdials-0.4.0 → cmsdials-1.0.0}/README.md +14 -13
  3. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/file_index/models.py +8 -9
  4. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/h1d/client.py +1 -1
  5. cmsdials-1.0.0/cmsdials/clients/h1d/models.py +49 -0
  6. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/h2d/client.py +1 -1
  7. cmsdials-1.0.0/cmsdials/clients/h2d/models.py +52 -0
  8. cmsdials-1.0.0/cmsdials/clients/lumisection/client.py +27 -0
  9. cmsdials-1.0.0/cmsdials/clients/lumisection/models.py +34 -0
  10. cmsdials-1.0.0/cmsdials/clients/run/client.py +27 -0
  11. cmsdials-1.0.0/cmsdials/clients/run/models.py +28 -0
  12. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/cmsdials.py +6 -8
  13. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/utils/api_client.py +13 -45
  14. cmsdials-1.0.0/pyproject.toml +126 -0
  15. cmsdials-0.4.0/cmsdials/clients/h1d/models.py +0 -43
  16. cmsdials-0.4.0/cmsdials/clients/h2d/models.py +0 -46
  17. cmsdials-0.4.0/cmsdials/clients/lumisection/client.py +0 -9
  18. cmsdials-0.4.0/cmsdials/clients/lumisection/models.py +0 -29
  19. cmsdials-0.4.0/cmsdials/clients/run/client.py +0 -9
  20. cmsdials-0.4.0/cmsdials/clients/run/models.py +0 -23
  21. cmsdials-0.4.0/pyproject.toml +0 -31
  22. {cmsdials-0.4.0 → cmsdials-1.0.0}/LICENSE +0 -0
  23. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/__init__.py +0 -0
  24. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/auth/__init__.py +0 -0
  25. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/auth/_base.py +0 -0
  26. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/auth/bearer.py +0 -0
  27. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/auth/client.py +0 -0
  28. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/auth/exceptions.py +0 -0
  29. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/auth/models.py +0 -0
  30. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/auth/secret_key.py +0 -0
  31. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/__init__.py +0 -0
  32. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/file_index/__init__.py +0 -0
  33. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/file_index/client.py +0 -0
  34. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/h1d/__init__.py +0 -0
  35. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/h2d/__init__.py +0 -0
  36. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/lumisection/__init__.py +0 -0
  37. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/clients/run/__init__.py +0 -0
  38. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/filters.py +0 -0
  39. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/utils/__init__.py +0 -0
  40. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/utils/_json.py +0 -0
  41. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/utils/base_model.py +0 -0
  42. {cmsdials-0.4.0 → cmsdials-1.0.0}/cmsdials/utils/logger.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cmsdials
3
- Version: 0.4.0
3
+ Version: 1.0.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
7
7
  Author-email: gabrielmscampos@gmail.com
8
8
  Requires-Python: >=3.9,<4.0
9
- Classifier: Development Status :: 4 - Beta
9
+ Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python
12
12
  Classifier: Programming Language :: Python :: 3
@@ -76,10 +76,10 @@ from cmsdials import Dials
76
76
  from cmsdials.filters import LumisectionHistogram1DFilters
77
77
 
78
78
  creds = Credentials.from_creds_file()
79
- dials = Dials(creds, nthreads=2)
79
+ dials = Dials(creds)
80
80
 
81
81
  # Getting h1d data
82
- data = dials.h1d.list_all(LumisectionHistogram1DFilters(title="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"), max_pages=5)
82
+ data = dials.h1d.list_all(LumisectionHistogram1DFilters(me="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"), max_pages=5)
83
83
  ```
84
84
 
85
85
  ### Workspace
@@ -87,7 +87,7 @@ data = dials.h1d.list_all(LumisectionHistogram1DFilters(title="PixelPhase1/Track
87
87
  Users are automatically routed to a workspace based on e-groups, but it is possible to overwrite this configuration and inspect data from others workspaces:
88
88
 
89
89
  ```python
90
- dials = Dials(creds, workspace="jetmet", nthreads=2)
90
+ dials = Dials(creds, workspace="jetmet")
91
91
  ```
92
92
 
93
93
  ## Available endpoints
@@ -97,11 +97,11 @@ This package interacts with DIALS api endpoints using underlying classes in `Dia
97
97
  ### Retrieving a specific object using `get`
98
98
 
99
99
  ```python
100
- dials.file_index.get(id=1)
100
+ dials.file_index.get(id=3386119397)
101
101
  dials.h1d.get(id=1)
102
102
  dials.h2d.get(id=1)
103
- dials.lumi.get(id=1)
104
- dials.run.get(id=1)
103
+ dials.lumi.get(dataset_id=14677060, run_number=367094, ls_number=1)
104
+ dials.run.get(dataset_id=14677060, run_number=367094)
105
105
  ```
106
106
 
107
107
  ### Retrieving a list of objects per page using `list`
@@ -118,6 +118,8 @@ dials.run.list()
118
118
 
119
119
  ### Retrieving all available pages of a list of objects using `list_all`
120
120
 
121
+ 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.
122
+
121
123
  ```python
122
124
  dials.file_index.list_all()
123
125
  dials.h1d.list_all()
@@ -145,16 +147,15 @@ from cmsdials.filters import (
145
147
  RunFilters
146
148
  )
147
149
 
150
+ dials.file_index.list(FileIndexFilters(dataset__regex="2024B"))
148
151
 
149
- dials.file_index.list(FileIndexFilters(page="10"))
150
-
151
- dials.h1d.list(LumisectionHistogram1DFilters(title="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2", page="15"))
152
+ dials.h1d.list(LumisectionHistogram1DFilters(me="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"))
152
153
 
153
- dials.h2d.list_all(LumisectionHistogram2DFilters(title_contains="EEOT digi occupancy EE +", min_entries=100, min_run_number=360392, max_run_number=365000), max_pages=5)
154
+ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), max_pages=5)
154
155
 
155
156
  dials.lumi.list_all(LumisectionFilters(run_number=360392), max_pages=5)
156
157
 
157
- dials.run.list_all(RunFilters(min_run_number=360392, max_run_number=365000), max_pages=5)
158
+ dials.run.list_all(RunFilters(run_number__gte=360392, run_number__lte=365000), max_pages=5)
158
159
  ```
159
160
 
160
161
  ### Dials MEs
@@ -180,8 +181,8 @@ DEV_CACHE_DIR = ".cache-dev"
180
181
 
181
182
  auth = AuthClient(base_url=DEV_URL)
182
183
  creds = Credentials.from_creds_file(cache_dir=DEV_CACHE_DIR, client=auth) # Make sure to specify the auth client with overwritten values, using another cache_dir is recommended
183
- dials = Dials(creds, nthreads=2, base_url=DEV_URL)
184
+ dials = Dials(creds, base_url=DEV_URL)
184
185
 
185
- dials.h2d.list_all(LumisectionHistogram2DFilters(title_contains="EEOT digi occupancy EE +", min_entries=100, min_run_number=360392, max_run_number=365000), max_pages=5)
186
+ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="EEOT digi occupancy EE +", entries__gte=100, run_number__gte=360392, run_number__lte=365000), max_pages=5)
186
187
  ```
187
188
 
@@ -53,10 +53,10 @@ from cmsdials import Dials
53
53
  from cmsdials.filters import LumisectionHistogram1DFilters
54
54
 
55
55
  creds = Credentials.from_creds_file()
56
- dials = Dials(creds, nthreads=2)
56
+ dials = Dials(creds)
57
57
 
58
58
  # Getting h1d data
59
- data = dials.h1d.list_all(LumisectionHistogram1DFilters(title="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"), max_pages=5)
59
+ data = dials.h1d.list_all(LumisectionHistogram1DFilters(me="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"), max_pages=5)
60
60
  ```
61
61
 
62
62
  ### Workspace
@@ -64,7 +64,7 @@ data = dials.h1d.list_all(LumisectionHistogram1DFilters(title="PixelPhase1/Track
64
64
  Users are automatically routed to a workspace based on e-groups, but it is possible to overwrite this configuration and inspect data from others workspaces:
65
65
 
66
66
  ```python
67
- dials = Dials(creds, workspace="jetmet", nthreads=2)
67
+ dials = Dials(creds, workspace="jetmet")
68
68
  ```
69
69
 
70
70
  ## Available endpoints
@@ -74,11 +74,11 @@ This package interacts with DIALS api endpoints using underlying classes in `Dia
74
74
  ### Retrieving a specific object using `get`
75
75
 
76
76
  ```python
77
- dials.file_index.get(id=1)
77
+ dials.file_index.get(id=3386119397)
78
78
  dials.h1d.get(id=1)
79
79
  dials.h2d.get(id=1)
80
- dials.lumi.get(id=1)
81
- dials.run.get(id=1)
80
+ dials.lumi.get(dataset_id=14677060, run_number=367094, ls_number=1)
81
+ dials.run.get(dataset_id=14677060, run_number=367094)
82
82
  ```
83
83
 
84
84
  ### Retrieving a list of objects per page using `list`
@@ -95,6 +95,8 @@ dials.run.list()
95
95
 
96
96
  ### Retrieving all available pages of a list of objects using `list_all`
97
97
 
98
+ 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.
99
+
98
100
  ```python
99
101
  dials.file_index.list_all()
100
102
  dials.h1d.list_all()
@@ -122,16 +124,15 @@ from cmsdials.filters import (
122
124
  RunFilters
123
125
  )
124
126
 
127
+ dials.file_index.list(FileIndexFilters(dataset__regex="2024B"))
125
128
 
126
- dials.file_index.list(FileIndexFilters(page="10"))
127
-
128
- dials.h1d.list(LumisectionHistogram1DFilters(title="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2", page="15"))
129
+ dials.h1d.list(LumisectionHistogram1DFilters(me="PixelPhase1/Tracks/PXBarrel/charge_PXLayer_2"))
129
130
 
130
- dials.h2d.list_all(LumisectionHistogram2DFilters(title_contains="EEOT digi occupancy EE +", min_entries=100, min_run_number=360392, max_run_number=365000), max_pages=5)
131
+ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="PXBarrel", ls_number=78, entries__gte=100), max_pages=5)
131
132
 
132
133
  dials.lumi.list_all(LumisectionFilters(run_number=360392), max_pages=5)
133
134
 
134
- dials.run.list_all(RunFilters(min_run_number=360392, max_run_number=365000), max_pages=5)
135
+ dials.run.list_all(RunFilters(run_number__gte=360392, run_number__lte=365000), max_pages=5)
135
136
  ```
136
137
 
137
138
  ### Dials MEs
@@ -157,7 +158,7 @@ DEV_CACHE_DIR = ".cache-dev"
157
158
 
158
159
  auth = AuthClient(base_url=DEV_URL)
159
160
  creds = Credentials.from_creds_file(cache_dir=DEV_CACHE_DIR, client=auth) # Make sure to specify the auth client with overwritten values, using another cache_dir is recommended
160
- dials = Dials(creds, nthreads=2, base_url=DEV_URL)
161
+ dials = Dials(creds, base_url=DEV_URL)
161
162
 
162
- dials.h2d.list_all(LumisectionHistogram2DFilters(title_contains="EEOT digi occupancy EE +", min_entries=100, min_run_number=360392, max_run_number=365000), max_pages=5)
163
+ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="EEOT digi occupancy EE +", entries__gte=100, run_number__gte=360392, run_number__lte=365000), max_pages=5)
163
164
  ```
@@ -7,11 +7,10 @@ from ...utils.base_model import OBaseModel
7
7
 
8
8
 
9
9
  class FileIndex(BaseModel):
10
+ dataset_id: int
11
+ dataset: str = Field(..., max_length=255)
10
12
  file_id: int
11
13
  file_size: int
12
- era: str = Field(..., max_length=5)
13
- campaign: str = Field(..., max_length=15)
14
- primary_dataset: str = Field(..., max_length=50)
15
14
  creation_date: datetime
16
15
  last_modification_date: datetime
17
16
  logical_file_name: str
@@ -20,17 +19,17 @@ class FileIndex(BaseModel):
20
19
 
21
20
 
22
21
  class PaginatedFileIndexList(BaseModel):
23
- count: int
24
22
  next: Optional[AnyUrl]
25
23
  previous: Optional[AnyUrl]
26
24
  results: List[FileIndex]
27
25
 
28
26
 
29
27
  class FileIndexFilters(OBaseModel):
30
- page: Optional[str] = None
31
- min_size: Optional[int] = None
32
- era: Optional[str] = None
33
- campaign: Optional[str] = None
34
- primary_dataset: Optional[str] = None
28
+ next_token: Optional[str] = None
29
+ dataset_id: Optional[int] = None
35
30
  logical_file_name: Optional[str] = None
31
+ logical_file_name__regex: Optional[str] = None
36
32
  status: Optional[str] = None
33
+ min_size: Optional[int] = None
34
+ dataset: Optional[str] = None
35
+ dataset__regex: Optional[str] = None
@@ -6,4 +6,4 @@ class LumisectionHistogram1DClient(BaseAuthorizedAPIClient):
6
6
  data_model = LumisectionHistogram1D
7
7
  pagination_model = PaginatedLumisectionHistogram1DList
8
8
  filter_class = LumisectionHistogram1DFilters
9
- lookup_url = "lumisection-h1d/"
9
+ lookup_url = "th1/"
@@ -0,0 +1,49 @@
1
+ from typing import List, Optional
2
+
3
+ from pydantic import AnyUrl, BaseModel, Field
4
+
5
+ from ...utils.base_model import OBaseModel
6
+
7
+
8
+ class LumisectionHistogram1D(BaseModel):
9
+ hist_id: int
10
+ dataset: str = Field(..., max_length=255)
11
+ me: str = Field(..., max_length=255)
12
+ dataset_id: int
13
+ file_id: int
14
+ run_number: int
15
+ ls_number: int
16
+ me_id: int
17
+ ls_id: int
18
+ x_min: float
19
+ x_max: float
20
+ x_bin: float
21
+ entries: int
22
+ data: list[float]
23
+
24
+
25
+ class PaginatedLumisectionHistogram1DList(BaseModel):
26
+ next: Optional[AnyUrl]
27
+ previous: Optional[AnyUrl]
28
+ results: List[LumisectionHistogram1D]
29
+
30
+
31
+ class LumisectionHistogram1DFilters(OBaseModel):
32
+ next_token: Optional[str] = None
33
+ dataset_id: Optional[int] = None
34
+ file_id: Optional[int] = None
35
+ run_number: Optional[int] = None
36
+ run_number__lte: Optional[int] = None
37
+ run_number__gte: Optional[int] = None
38
+ ls_number: Optional[int] = None
39
+ ls_numbet__lte: Optional[int] = None
40
+ ls_number__gte: Optional[int] = None
41
+ me_id: Optional[int] = None
42
+ ls_id: Optional[int] = None
43
+ entries__gte: Optional[int] = None
44
+ dataset: Optional[str] = None
45
+ dataset__regex: Optional[str] = None
46
+ logical_file_name: Optional[str] = None
47
+ logical_file_name__regex: Optional[str] = None
48
+ me: Optional[str] = None
49
+ me__regex: Optional[str] = None
@@ -6,4 +6,4 @@ class LumisectionHistogram2DClient(BaseAuthorizedAPIClient):
6
6
  data_model = LumisectionHistogram2D
7
7
  pagination_model = PaginatedLumisectionHistogram2DList
8
8
  filter_class = LumisectionHistogram2DFilters
9
- lookup_url = "lumisection-h2d/"
9
+ lookup_url = "th2/"
@@ -0,0 +1,52 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import AnyUrl, BaseModel, Field
4
+
5
+ from ...utils.base_model import OBaseModel
6
+
7
+
8
+ class LumisectionHistogram2D(BaseModel):
9
+ hist_id: int
10
+ dataset: str = Field(..., max_length=255)
11
+ me: str = Field(..., max_length=255)
12
+ dataset_id: int
13
+ file_id: int
14
+ run_number: int
15
+ ls_number: int
16
+ me_id: int
17
+ ls_id: int
18
+ x_min: float
19
+ x_max: float
20
+ x_bin: float
21
+ y_min: float
22
+ y_max: float
23
+ y_bin: float
24
+ entries: int
25
+ data: list[list[float]]
26
+
27
+
28
+ class PaginatedLumisectionHistogram2DList(BaseModel):
29
+ next: Optional[AnyUrl]
30
+ previous: Optional[AnyUrl]
31
+ results: list[LumisectionHistogram2D]
32
+
33
+
34
+ class LumisectionHistogram2DFilters(OBaseModel):
35
+ next_token: Optional[str] = None
36
+ dataset_id: Optional[int] = None
37
+ file_id: Optional[int] = None
38
+ run_number: Optional[int] = None
39
+ run_number__lte: Optional[int] = None
40
+ run_number__gte: Optional[int] = None
41
+ ls_number: Optional[int] = None
42
+ ls_numbet__lte: Optional[int] = None
43
+ ls_number__gte: Optional[int] = None
44
+ me_id: Optional[int] = None
45
+ ls_id: Optional[int] = None
46
+ entries__gte: Optional[int] = None
47
+ dataset: Optional[str] = None
48
+ dataset__regex: Optional[str] = None
49
+ logical_file_name: Optional[str] = None
50
+ logical_file_name__regex: Optional[str] = None
51
+ me: Optional[str] = None
52
+ me__regex: Optional[str] = None
@@ -0,0 +1,27 @@
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)
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)
@@ -0,0 +1,34 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import AnyUrl, BaseModel, Field
4
+
5
+ from ...utils.base_model import OBaseModel
6
+
7
+
8
+ class Lumisection(BaseModel):
9
+ dataset_id: int
10
+ dataset: str = Field(..., max_length=255)
11
+ run_number: int
12
+ ls_number: int
13
+ ls_id: int
14
+ th1_count: int
15
+ th2_count: int
16
+
17
+
18
+ class PaginatedLumisectionList(BaseModel):
19
+ next: Optional[AnyUrl]
20
+ previous: Optional[AnyUrl]
21
+ results: list[Lumisection]
22
+
23
+
24
+ class LumisectionFilters(OBaseModel):
25
+ next_token: Optional[str] = None
26
+ dataset_id: Optional[int] = None
27
+ run_number: Optional[int] = None
28
+ run_number__lte: Optional[int] = None
29
+ run_number__gte: Optional[int] = None
30
+ ls_number: Optional[int] = None
31
+ ls_number__lte: Optional[int] = None
32
+ ls_number__gte: Optional[int] = None
33
+ dataset: Optional[str] = None
34
+ dataset__regex: Optional[str] = None
@@ -0,0 +1,27 @@
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)
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)
@@ -0,0 +1,28 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import AnyUrl, BaseModel, Field
4
+
5
+ from ...utils.base_model import OBaseModel
6
+
7
+
8
+ class Run(BaseModel):
9
+ dataset_id: int
10
+ dataset: str = Field(..., max_length=255)
11
+ run_number: int
12
+ ls_count: int
13
+
14
+
15
+ class PaginatedRunList(BaseModel):
16
+ next: Optional[AnyUrl]
17
+ previous: Optional[AnyUrl]
18
+ results: list[Run]
19
+
20
+
21
+ class RunFilters(OBaseModel):
22
+ next_token: Optional[str] = None
23
+ dataset_id: Optional[int] = None
24
+ run_number: Optional[int] = None
25
+ run_number__lte: Optional[int] = None
26
+ run_number__gte: Optional[int] = None
27
+ dataset: Optional[str] = None
28
+ dataset__regex: Optional[str] = None
@@ -9,11 +9,9 @@ from .clients.run.client import RunClient
9
9
 
10
10
 
11
11
  class Dials:
12
- def __init__(
13
- self, creds: BaseCredentials, workspace: Optional[str] = None, nthreads: Optional[int] = None, *args, **kwargs
14
- ) -> None:
15
- self.file_index = FileIndexClient(creds, workspace, nthreads, *args, **kwargs)
16
- self.h1d = LumisectionHistogram1DClient(creds, workspace, nthreads, *args, **kwargs)
17
- self.h2d = LumisectionHistogram2DClient(creds, workspace, nthreads, *args, **kwargs)
18
- self.lumi = LumisectionClient(creds, workspace, nthreads, *args, **kwargs)
19
- self.run = RunClient(creds, workspace, nthreads, *args, **kwargs)
12
+ def __init__(self, creds: BaseCredentials, workspace: Optional[str] = None, *args, **kwargs) -> None:
13
+ self.file_index = FileIndexClient(creds, workspace, *args, **kwargs)
14
+ self.h1d = LumisectionHistogram1DClient(creds, workspace, *args, **kwargs)
15
+ self.h2d = LumisectionHistogram2DClient(creds, workspace, *args, **kwargs)
16
+ self.lumi = LumisectionClient(creds, workspace, *args, **kwargs)
17
+ self.run = RunClient(creds, workspace, *args, **kwargs)
@@ -1,6 +1,5 @@
1
- from concurrent.futures import ThreadPoolExecutor
2
- from math import ceil
3
1
  from typing import Optional
2
+ from urllib.parse import parse_qs, urlparse
4
3
 
5
4
  import requests
6
5
  from requests.exceptions import HTTPError
@@ -42,25 +41,23 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
42
41
  self,
43
42
  creds: BaseCredentials,
44
43
  workspace: Optional[str] = None,
45
- nthreads: Optional[int] = None,
46
44
  *args: str,
47
45
  **kwargs: str,
48
46
  ) -> None:
49
47
  super().__init__(*args, **kwargs)
50
48
  self.creds = creds
51
49
  self.workspace = workspace
52
- self.nthreads = nthreads or 1
53
50
 
54
- def __build_headers(self) -> dict:
51
+ def _build_headers(self) -> dict:
55
52
  base = {"accept": "application/json"}
56
53
  if self.workspace is not None:
57
54
  base["Workspace"] = self.workspace
58
55
  self.creds.before_request(base)
59
56
  return base
60
57
 
61
- def get(self, id: str):
58
+ def get(self, id: int):
62
59
  endpoint_url = self.api_url + self.lookup_url + str(id) + "/"
63
- headers = self.__build_headers()
60
+ headers = self._build_headers()
64
61
  response = requests.get(endpoint_url, headers=headers)
65
62
 
66
63
  try:
@@ -75,7 +72,7 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
75
72
  def list(self, filters=None):
76
73
  filters = filters or self.filter_class()
77
74
  endpoint_url = self.api_url + self.lookup_url
78
- headers = self.__build_headers()
75
+ headers = self._build_headers()
79
76
  response = requests.get(endpoint_url, headers=headers, params=filters.cleandict())
80
77
 
81
78
  try:
@@ -88,54 +85,25 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
88
85
  return self.pagination_model(**response)
89
86
 
90
87
  def __list_sync(self, filters, max_pages: Optional[int] = None):
91
- page = 1
88
+ next_token = None
92
89
  results = []
93
90
  is_last_page = False
91
+ total_pages = 0
94
92
 
95
93
  while is_last_page is False:
96
94
  curr_filters = self.filter_class(**filters.dict())
97
- curr_filters.page = str(page)
95
+ curr_filters.next_token = next_token
98
96
  response = self.list(curr_filters)
99
97
  results.extend(response.results)
100
98
  is_last_page = response.next is None
101
- page += 1
102
- if max_pages and page > max_pages:
99
+ next_token = parse_qs(urlparse(response.next).query).get("next_token") if response.next else None
100
+ total_pages += 1
101
+ if max_pages and total_pages > max_pages:
103
102
  break
104
103
 
105
104
  return self.pagination_model(
106
- count=response.count, next=None, previous=None, results=results # No problem re-using last response count
105
+ next=None, previous=None, results=results # No problem re-using last response count
107
106
  )
108
107
 
109
- def __list_multithreaded(self, filters, max_pages: Optional[int] = None):
110
- results = []
111
-
112
- # Request the first page to compute number of pages
113
- curr_filters = self.filter_class(**filters.dict())
114
- curr_filters.page = "1"
115
- response = self.list(curr_filters)
116
- results.extend(response.results)
117
- count = response.count
118
- n_pages = ceil(response.count / 10)
119
- n_pages = max_pages if max_pages is not None and n_pages > max_pages else n_pages
120
-
121
- # If there isn't another page, just return current results
122
- if response.next is None:
123
- return response
124
-
125
- # Request other pages
126
- all_filters = [{**filters.dict(), "page": str(page)} for page in range(2, n_pages + 1)]
127
- all_filters = [self.filter_class(**filter) for filter in all_filters]
128
- with ThreadPoolExecutor(max_workers=self.nthreads) as executor:
129
- jobs = executor.map(self.list, all_filters)
130
- del all_filters
131
- [results.extend(job_result.results) for job_result in jobs]
132
- del jobs
133
-
134
- return self.pagination_model(count=count, next=None, previous=None, results=results)
135
-
136
108
  def list_all(self, filters, max_pages: Optional[int] = None):
137
- return (
138
- self.__list_sync(filters, max_pages)
139
- if self.nthreads is None
140
- else self.__list_multithreaded(filters, max_pages)
141
- )
109
+ return self.__list_sync(filters, max_pages)
@@ -0,0 +1,126 @@
1
+ [tool.poetry]
2
+ name = "cmsdials"
3
+ version = "1.0.0"
4
+ description = "The Python api client interface to DIALS service"
5
+ authors = ["Gabriel Moreira <gabrielmscampos@gmail.com>"]
6
+ readme = "README.md"
7
+ include = ["LICENSE"]
8
+ repository = "https://github.com/cms-DQM/dials-py"
9
+ classifiers = [
10
+ "Development Status :: 5 - Production/Stable",
11
+ "Programming Language :: Python",
12
+ "Operating System :: OS Independent",
13
+ "Topic :: Software Development :: Libraries :: Python Modules"
14
+ ]
15
+ packages = [
16
+ { include = "cmsdials" }
17
+ ]
18
+
19
+ [tool.poetry.dependencies]
20
+ python = "^3.9"
21
+ requests = "^2.31.0"
22
+ pydantic = "<2, >=1"
23
+ typing-extensions = "<4.6.0, >=3.6.6"
24
+
25
+ [tool.poetry.group.dev.dependencies]
26
+ pre-commit = "^3.6.2"
27
+ ruff = "^0.4.2"
28
+
29
+ [tool.ruff]
30
+ exclude = [
31
+ ".bzr",
32
+ ".direnv",
33
+ ".eggs",
34
+ ".git",
35
+ ".git-rewrite",
36
+ ".hg",
37
+ ".mypy_cache",
38
+ ".nox",
39
+ ".pants.d",
40
+ ".pytype",
41
+ ".ruff_cache",
42
+ ".svn",
43
+ ".tox",
44
+ ".venv",
45
+ "__pypackages__",
46
+ "_build",
47
+ "buck-out",
48
+ "build",
49
+ "dist",
50
+ "venv",
51
+ "virtualenvs",
52
+ ]
53
+ line-length = 120
54
+ indent-width = 4
55
+ target-version = "py310"
56
+
57
+ [tool.ruff.lint]
58
+ select = [
59
+ # pycodestyle
60
+ "E",
61
+ # Pyflakes
62
+ "F",
63
+ # pep8-naming
64
+ "N",
65
+ # pyupgrade
66
+ "UP",
67
+ # flake8-bugbear
68
+ "B",
69
+ # flake8-bandit
70
+ "S",
71
+ # flake8-blind-except
72
+ "BLE",
73
+ # flake8-builtins
74
+ "A",
75
+ # isort
76
+ "I",
77
+ # flake8-logging-format
78
+ "G",
79
+ # flake8-no-pep420
80
+ "INP",
81
+ # Ruff-specific rules
82
+ "RUF"
83
+ ]
84
+ ignore = [
85
+ # Disable eradicate (commented code removal)
86
+ "ERA001",
87
+ # Disable Conflicting lint rules,
88
+ # see https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
89
+ "W191",
90
+ "E501",
91
+ "E111",
92
+ "E117",
93
+ "D206",
94
+ "D300",
95
+ "Q000",
96
+ "Q001",
97
+ "Q002",
98
+ "Q003",
99
+ "COM812",
100
+ "COM819",
101
+ "ISC001",
102
+ "ISC002",
103
+ # Disable unused `noqa` directive
104
+ "RUF100",
105
+ ]
106
+ # Allow unused variables when underscore-prefixed:
107
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
108
+
109
+ [tool.ruff.lint.pycodestyle]
110
+ ignore-overlong-task-comments = true
111
+
112
+ [tool.ruff.lint.isort]
113
+ section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
114
+ lines-after-imports = 2
115
+
116
+ [tool.ruff.lint.per-file-ignores]
117
+ # Ignore "E402", "F403", "F405" (import violations) in __init__.py files.
118
+ # Ignore "S" (flake8-bandit) and "N802" (function name should be lowercase) in tests and docs.
119
+ # Ignore "RUF" (Ruff-specific rules) and "I" (isort) in migrations.
120
+ "__init__.py" = ["E402", "F403", "F405"]
121
+ "**/{tests,docs}/*" = ["E402", "F403", "F405", "S", "N802"]
122
+ "**/*test*.py" = ["E402", "F403", "F405", "S", "N802"]
123
+
124
+ [build-system]
125
+ requires = ["poetry-core"]
126
+ build-backend = "poetry.core.masonry.api"
@@ -1,43 +0,0 @@
1
- from typing import List, Optional
2
-
3
- from pydantic import AnyUrl, BaseModel, Field
4
-
5
- from ...utils.base_model import OBaseModel
6
-
7
-
8
- class LumisectionHistogram1D(BaseModel):
9
- hist_id: int
10
- file_id: int
11
- run_number: int
12
- ls_id: int
13
- title: str = Field(..., max_length=220)
14
- x_min: float
15
- x_max: float
16
- x_bin: float
17
- entries: int
18
- data: list[float]
19
-
20
-
21
- class PaginatedLumisectionHistogram1DList(BaseModel):
22
- count: int
23
- next: Optional[AnyUrl]
24
- previous: Optional[AnyUrl]
25
- results: List[LumisectionHistogram1D]
26
-
27
-
28
- class LumisectionHistogram1DFilters(OBaseModel):
29
- page: Optional[str] = None
30
- run_number: Optional[int] = None
31
- ls_number: Optional[int] = None
32
- ls_id: Optional[int] = None
33
- title: Optional[str] = None
34
- min_run_number: Optional[int] = None
35
- max_run_number: Optional[int] = None
36
- min_ls_number: Optional[int] = None
37
- max_ls_number: Optional[int] = None
38
- title_contains: Optional[str] = None
39
- min_entries: Optional[int] = None
40
- era: Optional[str] = None
41
- campaign: Optional[str] = None
42
- primary_dataset: Optional[str] = None
43
- file_id: Optional[int] = None
@@ -1,46 +0,0 @@
1
- from typing import Optional
2
-
3
- from pydantic import AnyUrl, BaseModel, Field
4
-
5
- from ...utils.base_model import OBaseModel
6
-
7
-
8
- class LumisectionHistogram2D(BaseModel):
9
- hist_id: int
10
- file_id: int
11
- run_number: int
12
- ls_id: int
13
- title: str = Field(..., max_length=220)
14
- x_min: float
15
- x_max: float
16
- x_bin: float
17
- y_min: float
18
- y_max: float
19
- y_bin: float
20
- entries: int
21
- data: list[float]
22
-
23
-
24
- class PaginatedLumisectionHistogram2DList(BaseModel):
25
- count: int
26
- next: Optional[AnyUrl]
27
- previous: Optional[AnyUrl]
28
- results: list[LumisectionHistogram2D]
29
-
30
-
31
- class LumisectionHistogram2DFilters(OBaseModel):
32
- page: Optional[str] = None
33
- run_number: Optional[int] = None
34
- ls_number: Optional[int] = None
35
- ls_id: Optional[int] = None
36
- title: Optional[str] = None
37
- min_run_number: Optional[int] = None
38
- max_run_number: Optional[int] = None
39
- min_ls_number: Optional[int] = None
40
- max_ls_number: Optional[int] = None
41
- title_contains: Optional[str] = None
42
- min_entries: Optional[int] = None
43
- era: Optional[str] = None
44
- campaign: Optional[str] = None
45
- primary_dataset: Optional[str] = None
46
- file_id: Optional[int] = None
@@ -1,9 +0,0 @@
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/"
@@ -1,29 +0,0 @@
1
- from typing import Optional
2
-
3
- from pydantic import AnyUrl, BaseModel
4
-
5
- from ...utils.base_model import OBaseModel
6
-
7
-
8
- class Lumisection(BaseModel):
9
- ls_id: int
10
- ls_number: int
11
- th1_count: int
12
- th2_count: int
13
-
14
-
15
- class PaginatedLumisectionList(BaseModel):
16
- count: int
17
- next: Optional[AnyUrl]
18
- previous: Optional[AnyUrl]
19
- results: list[Lumisection]
20
-
21
-
22
- class LumisectionFilters(OBaseModel):
23
- page: Optional[str] = None
24
- run_number: Optional[int] = None
25
- ls_number: Optional[int] = None
26
- min_ls_number: Optional[int] = None
27
- max_ls_number: Optional[int] = None
28
- min_run_number: Optional[int] = None
29
- max_run_number: Optional[int] = None
@@ -1,9 +0,0 @@
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/"
@@ -1,23 +0,0 @@
1
- from typing import Optional
2
-
3
- from pydantic import AnyUrl, BaseModel
4
-
5
- from ...utils.base_model import OBaseModel
6
-
7
-
8
- class Run(BaseModel):
9
- run_number: int
10
- ls_count: int
11
-
12
-
13
- class PaginatedRunList(BaseModel):
14
- count: int
15
- next: Optional[AnyUrl]
16
- previous: Optional[AnyUrl]
17
- results: list[Run]
18
-
19
-
20
- class RunFilters(OBaseModel):
21
- page: Optional[str] = None
22
- max_run_number: Optional[int] = None
23
- min_run_number: Optional[int] = None
@@ -1,31 +0,0 @@
1
- [tool.poetry]
2
- name = "cmsdials"
3
- version = "0.4.0"
4
- description = "The Python api client interface to DIALS service"
5
- authors = ["Gabriel Moreira <gabrielmscampos@gmail.com>"]
6
- readme = "README.md"
7
- include = ["LICENSE"]
8
- repository = "https://github.com/cms-DQM/dials-py"
9
- classifiers = [
10
- "Development Status :: 4 - Beta",
11
- "Programming Language :: Python",
12
- "Operating System :: OS Independent",
13
- "Topic :: Software Development :: Libraries :: Python Modules"
14
- ]
15
- packages = [
16
- { include = "cmsdials" }
17
- ]
18
-
19
- [tool.poetry.dependencies]
20
- python = "^3.9"
21
- requests = "^2.31.0"
22
- pydantic = "<2, >=1"
23
- typing-extensions = "<4.6.0, >=3.6.6"
24
-
25
-
26
- [tool.poetry.group.dev.dependencies]
27
- pre-commit = "^3.6.2"
28
-
29
- [build-system]
30
- requires = ["poetry-core"]
31
- build-backend = "poetry.core.masonry.api"
File without changes
File without changes
File without changes