cmsdials 1.8.0__tar.gz → 2.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 (89) hide show
  1. cmsdials-2.0.0/.gitlab-ci.yml +74 -0
  2. {cmsdials-1.8.0 → cmsdials-2.0.0}/PKG-INFO +2 -1
  3. {cmsdials-1.8.0 → cmsdials-2.0.0}/README.md +1 -0
  4. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/_version.py +16 -3
  5. cmsdials-2.0.0/cmsdials/clients/mes/client.py +17 -0
  6. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/ml_bad_lumisection/client.py +13 -7
  7. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/ml_bad_lumisection/models.py +1 -3
  8. cmsdials-2.0.0/cmsdials/clients/ml_models_index/models.py +47 -0
  9. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/run/models.py +1 -0
  10. cmsdials-2.0.0/cmsdials/clients/workspace/client.py +49 -0
  11. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/cmsdials.py +2 -0
  12. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials.egg-info/PKG-INFO +2 -1
  13. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials.egg-info/SOURCES.txt +3 -0
  14. {cmsdials-1.8.0 → cmsdials-2.0.0}/pyproject.toml +2 -2
  15. cmsdials-2.0.0/tests/integration/env.py +15 -0
  16. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_auth_client.py +6 -9
  17. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_file_index_client.py +12 -9
  18. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_h1d_client.py +34 -9
  19. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_h2d_client.py +34 -9
  20. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_lumisection_client.py +13 -9
  21. cmsdials-2.0.0/tests/integration/test_mes_client.py +31 -0
  22. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_oms_proxy_client.py +9 -8
  23. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_resume.py +8 -7
  24. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/integration/test_run_client.py +12 -9
  25. cmsdials-2.0.0/tests/integration/utils.py +9 -0
  26. cmsdials-2.0.0/tests/unit/__init__.py +0 -0
  27. cmsdials-1.8.0/.gitlab-ci.yml +0 -115
  28. cmsdials-1.8.0/cmsdials/clients/mes/client.py +0 -36
  29. cmsdials-1.8.0/cmsdials/clients/ml_models_index/models.py +0 -26
  30. cmsdials-1.8.0/tests/integration/test_mes_client.py +0 -49
  31. cmsdials-1.8.0/tests/integration/utils.py +0 -15
  32. {cmsdials-1.8.0 → cmsdials-2.0.0}/.coveragerc +0 -0
  33. {cmsdials-1.8.0 → cmsdials-2.0.0}/.editorconfig +0 -0
  34. {cmsdials-1.8.0 → cmsdials-2.0.0}/.gitignore +0 -0
  35. {cmsdials-1.8.0 → cmsdials-2.0.0}/.mailmap +0 -0
  36. {cmsdials-1.8.0 → cmsdials-2.0.0}/.pre-commit-config.yaml +0 -0
  37. {cmsdials-1.8.0 → cmsdials-2.0.0}/.tool-versions +0 -0
  38. {cmsdials-1.8.0 → cmsdials-2.0.0}/LICENSE +0 -0
  39. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/__init__.py +0 -0
  40. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/auth/__init__.py +0 -0
  41. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/auth/_base.py +0 -0
  42. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/auth/bearer.py +0 -0
  43. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/auth/client.py +0 -0
  44. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/auth/exceptions.py +0 -0
  45. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/auth/models.py +0 -0
  46. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/auth/secret_key.py +0 -0
  47. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/__init__.py +0 -0
  48. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/dataset_index/__init__.py +0 -0
  49. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/dataset_index/client.py +0 -0
  50. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/dataset_index/models.py +0 -0
  51. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/file_index/__init__.py +0 -0
  52. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/file_index/client.py +0 -0
  53. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/file_index/models.py +0 -0
  54. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/h1d/__init__.py +0 -0
  55. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/h1d/client.py +0 -0
  56. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/h1d/models.py +0 -0
  57. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/h2d/__init__.py +0 -0
  58. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/h2d/client.py +0 -0
  59. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/h2d/models.py +0 -0
  60. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/lumisection/__init__.py +0 -0
  61. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/lumisection/client.py +0 -0
  62. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/lumisection/models.py +0 -0
  63. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/mes/__init__.py +0 -0
  64. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/mes/models.py +0 -0
  65. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/ml_bad_lumisection/__init__.py +0 -0
  66. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/ml_models_index/__init__.py +0 -0
  67. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/ml_models_index/client.py +0 -0
  68. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/oms_proxy/__init__.py +0 -0
  69. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/oms_proxy/client.py +0 -0
  70. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/oms_proxy/models.py +0 -0
  71. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/run/__init__.py +0 -0
  72. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/clients/run/client.py +0 -0
  73. {cmsdials-1.8.0/cmsdials/utils → cmsdials-2.0.0/cmsdials/clients/workspace}/__init__.py +0 -0
  74. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/filters.py +0 -0
  75. {cmsdials-1.8.0/tests/integration → cmsdials-2.0.0/cmsdials/utils}/__init__.py +0 -0
  76. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/utils/_json.py +0 -0
  77. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/utils/api_client.py +0 -0
  78. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/utils/base_model.py +0 -0
  79. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials/utils/logger.py +0 -0
  80. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials.egg-info/dependency_links.txt +0 -0
  81. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials.egg-info/requires.txt +0 -0
  82. {cmsdials-1.8.0 → cmsdials-2.0.0}/cmsdials.egg-info/top_level.txt +0 -0
  83. {cmsdials-1.8.0 → cmsdials-2.0.0}/mypy.ini +0 -0
  84. {cmsdials-1.8.0 → cmsdials-2.0.0}/pytest.ini +0 -0
  85. {cmsdials-1.8.0 → cmsdials-2.0.0}/ruff.toml +0 -0
  86. {cmsdials-1.8.0 → cmsdials-2.0.0}/setup.cfg +0 -0
  87. {cmsdials-1.8.0/tests/unit → cmsdials-2.0.0/tests/integration}/__init__.py +0 -0
  88. {cmsdials-1.8.0 → cmsdials-2.0.0}/tests/unit/test_base_api_client.py +0 -0
  89. {cmsdials-1.8.0 → cmsdials-2.0.0}/tox.ini +0 -0
@@ -0,0 +1,74 @@
1
+ include:
2
+ - project: "cms-ppd/technical-support/ci-templates"
3
+ ref: release/v1
4
+ file:
5
+ - "templates/python/uv_build.yml"
6
+ - "templates/python/uv_publish.yml"
7
+ - "templates/gitlab/create_release.yml"
8
+
9
+ stages:
10
+ - test
11
+ - build
12
+ - publish
13
+ - create_release
14
+
15
+ ###########
16
+ # Run tests
17
+ ###########
18
+
19
+ test_matrix:
20
+ stage: test
21
+ parallel:
22
+ matrix:
23
+ - PYTHON_VERSION: ["3.9", "3.10", "3.11", "3.12"]
24
+ image: registry.cern.ch/docker.io/library/python:$PYTHON_VERSION
25
+ before_script:
26
+ - python -m pip install --upgrade pip
27
+ - pip install uv
28
+ - uv sync --all-groups --extra pandas --extra tqdm
29
+ script:
30
+ - uv run ruff format --check cmsdials tests
31
+ - uv run ruff check cmsdials tests
32
+ - uv run mypy cmsdials tests
33
+ - uv run pytest tests
34
+ coverage: "/TOTAL.+ ([0-9]{1,3}%)/"
35
+ artifacts:
36
+ reports:
37
+ coverage_report:
38
+ coverage_format: cobertura
39
+ path: coverage.xml
40
+ variables:
41
+ SECRET_KEY: "$SECRET_KEY"
42
+
43
+ ###############
44
+ # Build package
45
+ ###############
46
+
47
+ build:
48
+ extends: .uv_build
49
+ variables:
50
+ UV_SYNC_FLAGS: "--all-groups --extra pandas --extra tqdm"
51
+ needs:
52
+ - test_matrix
53
+
54
+ #################
55
+ # Publish to PyPI
56
+ #################
57
+
58
+ publish:
59
+ extends: .uv_publish
60
+ rules:
61
+ - if: $CI_COMMIT_TAG
62
+ needs:
63
+ - build
64
+
65
+ ##########################
66
+ # Create release in GitLab
67
+ ##########################
68
+
69
+ create_release:
70
+ extends: .create_gitlab_release
71
+ rules:
72
+ - if: $CI_COMMIT_TAG
73
+ needs:
74
+ - publish
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmsdials
3
- Version: 1.8.0
3
+ Version: 2.0.0
4
4
  Summary: The Python api client interface to DIALS service
5
5
  Author-email: Gabriel Moreira <gabriel.moreira@cern.ch>
6
6
  Project-URL: Repository, https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py
@@ -372,6 +372,7 @@ Do not worry. The GitLab CI is configured to automatically publish the package o
372
372
 
373
373
  > [!NOTE]
374
374
  > For this to work the CI/CD variables named `UV_PUBLISH_TOKEN`, `GITLAB_TOKEN` should be registered in gitlab. The `UV_PUBLISH_TOKEN` is a api token access of CMSDQM organization and the `GITLAB_TOKEN` is a Project Access Token with api read/write rights, which is needed to read merge requests using the `glab-cli`.
375
+ > https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py/-/settings/access_tokens
375
376
 
376
377
  #### Manual
377
378
 
@@ -349,6 +349,7 @@ Do not worry. The GitLab CI is configured to automatically publish the package o
349
349
 
350
350
  > [!NOTE]
351
351
  > For this to work the CI/CD variables named `UV_PUBLISH_TOKEN`, `GITLAB_TOKEN` should be registered in gitlab. The `UV_PUBLISH_TOKEN` is a api token access of CMSDQM organization and the `GITLAB_TOKEN` is a Project Access Token with api read/write rights, which is needed to read merge requests using the `glab-cli`.
352
+ > https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py/-/settings/access_tokens
352
353
 
353
354
  #### Manual
354
355
 
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '1.8.0'
21
- __version_tuple__ = version_tuple = (1, 8, 0)
31
+ __version__ = version = '2.0.0'
32
+ __version_tuple__ = version_tuple = (2, 0, 0)
33
+
34
+ __commit_id__ = commit_id = 'g68ff6a70a'
@@ -0,0 +1,17 @@
1
+ from ...utils.api_client import BaseAuthorizedNonPaginatedAPIClient
2
+ from .models import MEFilters, MonitoringElement
3
+
4
+
5
+ class MonitoringElementClient(
6
+ BaseAuthorizedNonPaginatedAPIClient[
7
+ MonitoringElement,
8
+ MEFilters,
9
+ ]
10
+ ):
11
+ data_model = MonitoringElement
12
+ filter_class = MEFilters
13
+ lookup_url = "mes/"
14
+
15
+ def get(self, id: int, **kwargs): # noqa: A002
16
+ edp = f"{id}/"
17
+ return super()._get(edp, **kwargs)
@@ -18,18 +18,24 @@ class MLBadLumisectionClient(
18
18
  edp = f"{model_id}/{dataset_id}/{run_number}/{ls_number}/{me_id}/"
19
19
  return super()._get(edp, **kwargs)
20
20
 
21
- def cert_json(self, model_id__in: list[int], dataset_id__in: list[int], run_number__in: list[int], **kwargs):
22
- edp = "cert-json/"
21
+ def __json_params_builder(
22
+ self, model_id__in: list[int], dataset_id__in: list[int], run_number__in: list[int], **kwargs
23
+ ):
23
24
  midin = ",".join(str(v) for v in model_id__in)
24
25
  didin = ",".join(str(v) for v in dataset_id__in)
25
26
  ridin = ",".join(str(v) for v in run_number__in)
26
- params = {"model_id__in": midin, "dataset_id__in": didin, "run_number__in": ridin}
27
+ return {"model_id__in": midin, "dataset_id__in": didin, "run_number__in": ridin}
28
+
29
+ def cert_json(self, model_id__in: list[int], dataset_id__in: list[int], run_number__in: list[int], **kwargs):
30
+ edp = "cert-json/"
31
+ params = self.__json_params_builder(
32
+ model_id__in=model_id__in, dataset_id__in=dataset_id__in, run_number__in=run_number__in
33
+ )
27
34
  return super()._get(edp, params=params, return_raw_json=True, **kwargs)
28
35
 
29
36
  def golden_json(self, model_id__in: list[int], dataset_id__in: list[int], run_number__in: list[int], **kwargs):
30
37
  edp = "golden-json/"
31
- midin = ",".join(str(v) for v in model_id__in)
32
- didin = ",".join(str(v) for v in dataset_id__in)
33
- ridin = ",".join(str(v) for v in run_number__in)
34
- params = {"model_id__in": midin, "dataset_id__in": didin, "run_number__in": ridin}
38
+ params = self.__json_params_builder(
39
+ model_id__in=model_id__in, dataset_id__in=dataset_id__in, run_number__in=run_number__in
40
+ )
35
41
  return super()._get(edp, params=params, return_raw_json=True, **kwargs)
@@ -8,11 +8,9 @@ from ...utils.base_model import PaginatedBaseFilters, PaginatedBaseModel
8
8
  class MLBadLumisection(BaseModel):
9
9
  model_id: int
10
10
  dataset_id: int
11
- file_id: int
12
11
  run_number: int
13
12
  ls_number: int
14
- me_id: int
15
- mse: float
13
+ metric_value: float
16
14
 
17
15
 
18
16
  class PaginatedMLBadLumisectionList(PaginatedBaseModel[MLBadLumisection]):
@@ -0,0 +1,47 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from ...utils.base_model import PaginatedBaseFilters, PaginatedBaseModel
7
+
8
+
9
+ class MLModelsIndex(BaseModel):
10
+ id: int
11
+ name: str
12
+ revision: int
13
+ ready: bool
14
+ active: bool
15
+ type: str
16
+ anomaly_threshold: Optional[float]
17
+ builtin_threshold: bool
18
+ description: str
19
+ flagging_key: Optional[str]
20
+ input_signature: list[dict]
21
+ metric_key: Optional[str]
22
+ output_signature: list[dict]
23
+ tags: Optional[list[dict]]
24
+ isvc_service_name: Optional[str]
25
+ isvc_yaml: Optional[str]
26
+ created_by: str
27
+ modified_by: str
28
+ created_at: datetime
29
+ modified_at: datetime
30
+
31
+
32
+ class PaginatedMLModelsIndexList(PaginatedBaseModel[MLModelsIndex]):
33
+ pass
34
+
35
+
36
+ class MLModelsIndexFilters(PaginatedBaseFilters):
37
+ id: Optional[int] = None
38
+ id__in: Optional[list[int]] = None
39
+ name: Optional[str] = None
40
+ name__regex: Optional[str] = None
41
+ active: Optional[bool] = None
42
+ ready: Optional[bool] = None
43
+ type: Optional[str] = None
44
+ input_signature_contains_me: Optional[str] = None
45
+ input_signature_contains_me__regex: Optional[str] = None
46
+ tag_name: Optional[str] = None
47
+ tag_value: Optional[str] = None
@@ -10,6 +10,7 @@ class Run(BaseModel):
10
10
  dataset: str = Field(..., max_length=255)
11
11
  run_number: int
12
12
  ls_count: int
13
+ ls_completeness: Optional[float]
13
14
 
14
15
 
15
16
  class PaginatedRunList(PaginatedBaseModel[Run]):
@@ -0,0 +1,49 @@
1
+ from requests.adapters import DEFAULT_RETRIES
2
+ from requests.exceptions import HTTPError
3
+
4
+ from ...auth._base import BaseCredentials
5
+ from ...utils.api_client import BaseAPIClient
6
+ from ...utils.logger import logger
7
+
8
+
9
+ class WorkspaceClient(BaseAPIClient):
10
+ default_timeout = 30
11
+ lookup_url = "auth/"
12
+
13
+ def __init__(
14
+ self,
15
+ creds: BaseCredentials,
16
+ *args: str,
17
+ **kwargs: str,
18
+ ) -> None:
19
+ super().__init__(*args, **kwargs)
20
+ self.creds = creds
21
+
22
+ def _build_headers(self) -> dict:
23
+ base = {"Accept": "application/json", "User-Agent": self._build_user_agent()}
24
+ self.creds.before_request(base)
25
+ return base
26
+
27
+ def __get(self, endpoint: str, retries=DEFAULT_RETRIES):
28
+ headers = self._build_headers()
29
+ endpoint_url = self.api_url + self.lookup_url + endpoint
30
+
31
+ response = self._requests_get_retriable(
32
+ endpoint_url,
33
+ headers=headers,
34
+ timeout=self.default_timeout,
35
+ retries=retries,
36
+ )
37
+ try:
38
+ response.raise_for_status()
39
+ except HTTPError as err:
40
+ logger.info(f"Api raw response: {response.text}")
41
+ raise err
42
+
43
+ return response.json()
44
+
45
+ def list(self, retries=DEFAULT_RETRIES):
46
+ return self.__get("workspaces", retries=retries)
47
+
48
+ def my_workspace(self, retries=DEFAULT_RETRIES):
49
+ return self.__get("user-default-workspace", retries=retries)
@@ -11,6 +11,7 @@ from .clients.ml_bad_lumisection.client import MLBadLumisectionClient
11
11
  from .clients.ml_models_index.client import MLModelsIndexClient
12
12
  from .clients.oms_proxy.client import OMSProxyClient
13
13
  from .clients.run.client import RunClient
14
+ from .clients.workspace.client import WorkspaceClient
14
15
 
15
16
 
16
17
  class Dials:
@@ -25,3 +26,4 @@ class Dials:
25
26
  self.oms = OMSProxyClient(creds, *args, **kwargs)
26
27
  self.ml_bad_lumis = MLBadLumisectionClient(creds, workspace, *args, **kwargs)
27
28
  self.ml_models_index = MLModelsIndexClient(creds, workspace, *args, **kwargs)
29
+ self.workspace = WorkspaceClient(creds, *args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmsdials
3
- Version: 1.8.0
3
+ Version: 2.0.0
4
4
  Summary: The Python api client interface to DIALS service
5
5
  Author-email: Gabriel Moreira <gabriel.moreira@cern.ch>
6
6
  Project-URL: Repository, https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py
@@ -372,6 +372,7 @@ Do not worry. The GitLab CI is configured to automatically publish the package o
372
372
 
373
373
  > [!NOTE]
374
374
  > For this to work the CI/CD variables named `UV_PUBLISH_TOKEN`, `GITLAB_TOKEN` should be registered in gitlab. The `UV_PUBLISH_TOKEN` is a api token access of CMSDQM organization and the `GITLAB_TOKEN` is a Project Access Token with api read/write rights, which is needed to read merge requests using the `glab-cli`.
375
+ > https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py/-/settings/access_tokens
375
376
 
376
377
  #### Manual
377
378
 
@@ -59,12 +59,15 @@ cmsdials/clients/oms_proxy/models.py
59
59
  cmsdials/clients/run/__init__.py
60
60
  cmsdials/clients/run/client.py
61
61
  cmsdials/clients/run/models.py
62
+ cmsdials/clients/workspace/__init__.py
63
+ cmsdials/clients/workspace/client.py
62
64
  cmsdials/utils/__init__.py
63
65
  cmsdials/utils/_json.py
64
66
  cmsdials/utils/api_client.py
65
67
  cmsdials/utils/base_model.py
66
68
  cmsdials/utils/logger.py
67
69
  tests/integration/__init__.py
70
+ tests/integration/env.py
68
71
  tests/integration/test_auth_client.py
69
72
  tests/integration/test_file_index_client.py
70
73
  tests/integration/test_h1d_client.py
@@ -38,10 +38,10 @@ Repository = "https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py"
38
38
 
39
39
  [dependency-groups]
40
40
  lint = [
41
- "mypy>=1.15.0",
41
+ "mypy==1.15.0",
42
42
  "pandas-stubs>=2.2.2.240807",
43
43
  "pre-commit>=4.2.0",
44
- "ruff>=0.11.4",
44
+ "ruff==0.11.4",
45
45
  "types-requests>=2.31.0.6",
46
46
  "types-tqdm>=4.67.0.20250516",
47
47
  ]
@@ -0,0 +1,15 @@
1
+ import os
2
+
3
+
4
+ SECRET_KEY = os.getenv("SECRET_KEY")
5
+ if not SECRET_KEY:
6
+ raise OSError("SECRET_KEY environment variable is not set.")
7
+
8
+ BASE_URL = os.getenv("BASE_URL", "https://dev-cmsdials-api.web.cern.ch/")
9
+ TEST_WORKSPACE = os.getenv("TEST_WORKSPACE", "global")
10
+ TEST_DATASET_ID = int(os.getenv("TEST_DATASET_ID", 15310647)) # /ZeroBias/Run2025B-PromptReco-v1/DQMIO
11
+ TEST_FILE_ID = int(
12
+ os.getenv("TEST_FILE_ID", 22961052797)
13
+ ) # /store/data/Run2025B/ZeroBias/DQMIO/PromptReco-v1/000/392/158/00000/DC769215-780F-4D7D-B0B7-E66F731E3FC0.root
14
+ TEST_RUN_NUMBER = int(os.getenv("TEST_RUN_NUMBER", 392158))
15
+ TEST_LS_NUMBER = int(os.getenv("TEST_LS_NUMBER", 10))
@@ -1,4 +1,3 @@
1
- import os
2
1
  from datetime import datetime, timedelta
3
2
  from typing import Union
4
3
 
@@ -10,21 +9,19 @@ from cmsdials.auth.bearer import Credentials as BearerCredentials
10
9
  from cmsdials.auth.client import AuthClient
11
10
  from cmsdials.auth.models import Token
12
11
  from cmsdials.auth.secret_key import Credentials as SecretKeyCredentials
13
- from cmsdials.clients.h1d.models import LumisectionHistogram1D
14
12
 
15
-
16
- BASE_URL = os.getenv("BASE_URL")
13
+ from .env import BASE_URL, SECRET_KEY, TEST_WORKSPACE
17
14
 
18
15
 
19
16
  def __setup_dials_from_creds_and_test(creds: Union[SecretKeyCredentials, BearerCredentials]) -> None:
20
- dials = Dials(creds, base_url=BASE_URL)
21
- data = dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=1)
22
- assert isinstance(data, LumisectionHistogram1D)
17
+ dials = Dials(creds, workspace=TEST_WORKSPACE, base_url=BASE_URL)
18
+ # just test if we can access the workspace endpoints
19
+ dials.workspace.my_workspace()
20
+ dials.workspace.list()
23
21
 
24
22
 
25
23
  def test_secret_key_success() -> None:
26
- secret_key = os.getenv("SECRET_KEY")
27
- creds = SecretKeyCredentials(token=secret_key)
24
+ creds = SecretKeyCredentials(token=SECRET_KEY)
28
25
  __setup_dials_from_creds_and_test(creds)
29
26
 
30
27
 
@@ -4,44 +4,47 @@ from urllib3.util import Retry
4
4
  from cmsdials.clients.file_index.models import FileIndex, PaginatedFileIndexList
5
5
  from cmsdials.filters import FileIndexFilters
6
6
 
7
- from .utils import DEFAULT_TEST_WORKSPACE, setup_dials_object
7
+ from .env import TEST_DATASET_ID, TEST_FILE_ID
8
+ from .utils import setup_dials_object
8
9
 
9
10
 
10
11
  def test_get_file_index() -> None:
11
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
12
- data = dials.file_index.get(dataset_id=14677060, file_id=3393809397)
12
+ dials = setup_dials_object()
13
+ data = dials.file_index.get(dataset_id=TEST_DATASET_ID, file_id=TEST_FILE_ID)
13
14
  assert isinstance(data, FileIndex)
14
15
 
15
16
 
16
17
  def test_list_file_index() -> None:
17
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
18
+ dials = setup_dials_object()
18
19
  data = dials.file_index.list()
19
20
  assert isinstance(data, PaginatedFileIndexList)
20
21
  assert isinstance(data.to_pandas(), pd.DataFrame)
21
22
 
22
23
 
23
24
  def test_list_all_file_index() -> None:
24
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
25
+ dials = setup_dials_object()
25
26
  data = dials.file_index.list_all(FileIndexFilters(), max_pages=5)
26
27
  assert isinstance(data, PaginatedFileIndexList)
27
28
  assert isinstance(data.to_pandas(), pd.DataFrame)
28
29
 
29
30
 
30
31
  def test_get_file_index_with_retries() -> None:
31
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
32
- data = dials.file_index.get(dataset_id=14677060, file_id=3393809397, retries=Retry(total=3, backoff_factor=0.1))
32
+ dials = setup_dials_object()
33
+ data = dials.file_index.get(
34
+ dataset_id=TEST_DATASET_ID, file_id=TEST_FILE_ID, retries=Retry(total=3, backoff_factor=0.1)
35
+ )
33
36
  assert isinstance(data, FileIndex)
34
37
 
35
38
 
36
39
  def test_list_file_index_with_retries() -> None:
37
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
40
+ dials = setup_dials_object()
38
41
  data = dials.file_index.list(retries=Retry(total=3, backoff_factor=0.1))
39
42
  assert isinstance(data, PaginatedFileIndexList)
40
43
  assert isinstance(data.to_pandas(), pd.DataFrame)
41
44
 
42
45
 
43
46
  def test_list_all_file_index_with_retries() -> None:
44
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
47
+ dials = setup_dials_object()
45
48
  data = dials.file_index.list_all(FileIndexFilters(), max_pages=5, retries=Retry(total=3, backoff_factor=0.1))
46
49
  assert isinstance(data, PaginatedFileIndexList)
47
50
  assert isinstance(data.to_pandas(), pd.DataFrame)
@@ -4,46 +4,71 @@ from urllib3.util import Retry
4
4
  from cmsdials.clients.h1d.models import LumisectionHistogram1D, PaginatedLumisectionHistogram1DList
5
5
  from cmsdials.filters import LumisectionHistogram1DFilters
6
6
 
7
- from .utils import DEFAULT_TEST_WORKSPACE, setup_dials_object
7
+ from .env import TEST_DATASET_ID, TEST_LS_NUMBER, TEST_RUN_NUMBER
8
+ from .utils import setup_dials_object
8
9
 
9
10
 
10
11
  def test_get_h1d() -> None:
11
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
12
- data = dials.h1d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=1)
12
+ dials = setup_dials_object()
13
+
14
+ # Fetch any valid monitoring element ID with dimension 1 from the MEs endpoint
15
+ data = dials.mes.list()
16
+ me_id = None
17
+ for me in data:
18
+ if me.dim == 1:
19
+ me_id = me.me_id
20
+ break
21
+ assert me_id is not None, "No 1D Monitoring Element found in MEs endpoint"
22
+
23
+ data = dials.h1d.get(dataset_id=TEST_DATASET_ID, run_number=TEST_RUN_NUMBER, ls_number=TEST_LS_NUMBER, me_id=me_id)
13
24
  assert isinstance(data, LumisectionHistogram1D)
14
25
 
15
26
 
16
27
  def test_list_h1d() -> None:
17
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
28
+ dials = setup_dials_object()
18
29
  data = dials.h1d.list()
19
30
  assert isinstance(data, PaginatedLumisectionHistogram1DList)
20
31
  assert isinstance(data.to_pandas(), pd.DataFrame)
21
32
 
22
33
 
23
34
  def test_list_all_h1d() -> None:
24
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
35
+ dials = setup_dials_object()
25
36
  data = dials.h1d.list_all(LumisectionHistogram1DFilters(), max_pages=5)
26
37
  assert isinstance(data, PaginatedLumisectionHistogram1DList)
27
38
  assert isinstance(data.to_pandas(), pd.DataFrame)
28
39
 
29
40
 
30
41
  def test_get_h1d_with_retries() -> None:
31
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
42
+ dials = setup_dials_object()
43
+
44
+ # Fetch any valid monitoring element ID with dimension 1 from the MEs endpoint
45
+ data = dials.mes.list()
46
+ me_id = None
47
+ for me in data:
48
+ if me.dim == 1:
49
+ me_id = me.me_id
50
+ break
51
+ assert me_id is not None, "No 1D Monitoring Element found in MEs endpoint"
52
+
32
53
  data = dials.h1d.get(
33
- dataset_id=14677060, run_number=367112, ls_number=10, me_id=1, retries=Retry(total=3, backoff_factor=0.1)
54
+ dataset_id=TEST_DATASET_ID,
55
+ run_number=TEST_RUN_NUMBER,
56
+ ls_number=TEST_LS_NUMBER,
57
+ me_id=me_id,
58
+ retries=Retry(total=3, backoff_factor=0.1),
34
59
  )
35
60
  assert isinstance(data, LumisectionHistogram1D)
36
61
 
37
62
 
38
63
  def test_list_h1d_with_retries() -> None:
39
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
64
+ dials = setup_dials_object()
40
65
  data = dials.h1d.list(retries=Retry(total=3, backoff_factor=0.1))
41
66
  assert isinstance(data, PaginatedLumisectionHistogram1DList)
42
67
  assert isinstance(data.to_pandas(), pd.DataFrame)
43
68
 
44
69
 
45
70
  def test_list_all_h1d_with_retries() -> None:
46
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
71
+ dials = setup_dials_object()
47
72
  data = dials.h1d.list_all(LumisectionHistogram1DFilters(), max_pages=5, retries=Retry(total=5, backoff_factor=0.1))
48
73
  assert isinstance(data, PaginatedLumisectionHistogram1DList)
49
74
  assert isinstance(data.to_pandas(), pd.DataFrame)
@@ -4,46 +4,71 @@ from urllib3.util import Retry
4
4
  from cmsdials.clients.h2d.models import LumisectionHistogram2D, PaginatedLumisectionHistogram2DList
5
5
  from cmsdials.filters import LumisectionHistogram2DFilters
6
6
 
7
- from .utils import DEFAULT_TEST_WORKSPACE, setup_dials_object
7
+ from .env import TEST_DATASET_ID, TEST_LS_NUMBER, TEST_RUN_NUMBER
8
+ from .utils import setup_dials_object
8
9
 
9
10
 
10
11
  def test_get_h2d() -> None:
11
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
12
- data = dials.h2d.get(dataset_id=14677060, run_number=367112, ls_number=10, me_id=100)
12
+ dials = setup_dials_object()
13
+
14
+ # Fetch any valid monitoring element ID with dimension 2 from the MEs endpoint
15
+ data = dials.mes.list()
16
+ me_id = None
17
+ for me in data:
18
+ if me.dim == 2:
19
+ me_id = me.me_id
20
+ break
21
+ assert me_id is not None, "No 2D Monitoring Element found in MEs endpoint"
22
+
23
+ data = dials.h2d.get(dataset_id=TEST_DATASET_ID, run_number=TEST_RUN_NUMBER, ls_number=TEST_LS_NUMBER, me_id=me_id)
13
24
  assert isinstance(data, LumisectionHistogram2D)
14
25
 
15
26
 
16
27
  def test_list_h2d() -> None:
17
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
28
+ dials = setup_dials_object()
18
29
  data = dials.h2d.list()
19
30
  assert isinstance(data, PaginatedLumisectionHistogram2DList)
20
31
  assert isinstance(data.to_pandas(), pd.DataFrame)
21
32
 
22
33
 
23
34
  def test_list_all_h2d() -> None:
24
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
35
+ dials = setup_dials_object()
25
36
  data = dials.h2d.list_all(LumisectionHistogram2DFilters(), max_pages=5)
26
37
  assert isinstance(data, PaginatedLumisectionHistogram2DList)
27
38
  assert isinstance(data.to_pandas(), pd.DataFrame)
28
39
 
29
40
 
30
41
  def test_get_h2d_with_retries() -> None:
31
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
42
+ dials = setup_dials_object()
43
+
44
+ # Fetch any valid monitoring element ID with dimension 2 from the MEs endpoint
45
+ data = dials.mes.list()
46
+ me_id = None
47
+ for me in data:
48
+ if me.dim == 2:
49
+ me_id = me.me_id
50
+ break
51
+ assert me_id is not None, "No 2D Monitoring Element found in MEs endpoint"
52
+
32
53
  data = dials.h2d.get(
33
- dataset_id=14677060, run_number=367112, ls_number=10, me_id=100, retries=Retry(total=3, backoff_factor=0.1)
54
+ dataset_id=TEST_DATASET_ID,
55
+ run_number=TEST_RUN_NUMBER,
56
+ ls_number=TEST_LS_NUMBER,
57
+ me_id=me_id,
58
+ retries=Retry(total=3, backoff_factor=0.1),
34
59
  )
35
60
  assert isinstance(data, LumisectionHistogram2D)
36
61
 
37
62
 
38
63
  def test_list_h2d_with_retries() -> None:
39
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
64
+ dials = setup_dials_object()
40
65
  data = dials.h2d.list(retries=Retry(total=3, backoff_factor=0.1))
41
66
  assert isinstance(data, PaginatedLumisectionHistogram2DList)
42
67
  assert isinstance(data.to_pandas(), pd.DataFrame)
43
68
 
44
69
 
45
70
  def test_list_all_h2d_with_retries() -> None:
46
- dials = setup_dials_object(workspace=DEFAULT_TEST_WORKSPACE)
71
+ dials = setup_dials_object()
47
72
  data = dials.h2d.list_all(LumisectionHistogram2DFilters(), max_pages=5, retries=Retry(total=5, backoff_factor=0.1))
48
73
  assert isinstance(data, PaginatedLumisectionHistogram2DList)
49
74
  assert isinstance(data.to_pandas(), pd.DataFrame)