cmsdials 1.5.0__tar.gz → 1.7.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 (52) hide show
  1. {cmsdials-1.5.0 → cmsdials-1.7.0}/PKG-INFO +27 -6
  2. {cmsdials-1.5.0 → cmsdials-1.7.0}/README.md +24 -2
  3. cmsdials-1.7.0/cmsdials/__init__.py +5 -0
  4. cmsdials-1.7.0/cmsdials/_version.py +1 -0
  5. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/auth/bearer.py +1 -1
  6. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/auth/client.py +3 -0
  7. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/oms_proxy/client.py +4 -1
  8. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/utils/api_client.py +19 -7
  9. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/utils/base_model.py +1 -1
  10. {cmsdials-1.5.0 → cmsdials-1.7.0}/pyproject.toml +20 -6
  11. cmsdials-1.5.0/cmsdials/__init__.py +0 -4
  12. {cmsdials-1.5.0 → cmsdials-1.7.0}/LICENSE +0 -0
  13. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/auth/__init__.py +0 -0
  14. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/auth/_base.py +0 -0
  15. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/auth/exceptions.py +0 -0
  16. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/auth/models.py +0 -0
  17. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/auth/secret_key.py +0 -0
  18. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/__init__.py +0 -0
  19. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/dataset_index/__init__.py +0 -0
  20. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/dataset_index/client.py +0 -0
  21. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/dataset_index/models.py +0 -0
  22. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/file_index/__init__.py +0 -0
  23. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/file_index/client.py +0 -0
  24. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/file_index/models.py +0 -0
  25. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/h1d/__init__.py +0 -0
  26. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/h1d/client.py +0 -0
  27. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/h1d/models.py +0 -0
  28. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/h2d/__init__.py +0 -0
  29. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/h2d/client.py +0 -0
  30. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/h2d/models.py +0 -0
  31. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/lumisection/__init__.py +0 -0
  32. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/lumisection/client.py +0 -0
  33. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/lumisection/models.py +0 -0
  34. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/mes/__init__.py +0 -0
  35. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/mes/client.py +0 -0
  36. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/mes/models.py +0 -0
  37. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/ml_bad_lumisection/__init__.py +0 -0
  38. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/ml_bad_lumisection/client.py +0 -0
  39. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/ml_bad_lumisection/models.py +0 -0
  40. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/ml_models_index/__init__.py +0 -0
  41. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/ml_models_index/client.py +0 -0
  42. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/ml_models_index/models.py +0 -0
  43. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/oms_proxy/__init__.py +0 -0
  44. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/oms_proxy/models.py +0 -0
  45. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/run/__init__.py +0 -0
  46. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/run/client.py +0 -0
  47. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/clients/run/models.py +0 -0
  48. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/cmsdials.py +0 -0
  49. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/filters.py +0 -0
  50. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/utils/__init__.py +0 -0
  51. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/utils/_json.py +0 -0
  52. {cmsdials-1.5.0 → cmsdials-1.7.0}/cmsdials/utils/logger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cmsdials
3
- Version: 1.5.0
3
+ Version: 1.7.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
@@ -18,14 +18,17 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
18
  Provides-Extra: pandas
19
19
  Provides-Extra: tqdm
20
20
  Requires-Dist: pandas (>=1.5.3) ; extra == "pandas"
21
- Requires-Dist: pydantic (>=1,<2)
21
+ Requires-Dist: pydantic (>=2.8.2,<3.0.0)
22
22
  Requires-Dist: requests (>=2.31.0,<3.0.0)
23
23
  Requires-Dist: tqdm (>=4.66.1) ; extra == "tqdm"
24
- Requires-Dist: typing-extensions (>=3.6.6,<4.6.0)
25
- Requires-Dist: urllib3 (>=2.2.3,<3.0.0)
24
+ Requires-Dist: urllib3 (>=1.26.16,<2.0.0)
26
25
  Project-URL: Repository, https://github.com/cms-DQM/dials-py
27
26
  Description-Content-Type: text/markdown
28
27
 
28
+ ![Build Status](https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py/badges/dev/pipeline.svg)
29
+ ![Coverage](https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py/badges/dev/coverage.svg)
30
+ [![PyPI version](https://badge.fury.io/py/cmsdials.png)](https://badge.fury.io/py/cmsdials)
31
+
29
32
  # dials-py
30
33
 
31
34
  The Python api client interface to DIALS service.
@@ -322,7 +325,7 @@ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="EEOT digi occupancy
322
325
  The repository has some tests written to make sure DIALS responses are compatible with pydantic metaclasses, you can use pytest to run all tests but you need to specify a secret key to authenticate non-interactively against DIALS api:
323
326
 
324
327
  ```bash
325
- SECRET_KEY=... pytest tests
328
+ SECRET_KEY=... pytest tests --cov=cmsdials --cov-report=xml --cov-report=term --cov-report=html
326
329
  ```
327
330
 
328
331
  The secret key is an api client enabled secret key and can be obtained from the applications portal, any api client secret key whitelisted in DIALS can be used. The interactive authentication flow should be tested manually, an example for this can be found in [this line](/tests/integration/test_auth_client.py#L33).
@@ -330,6 +333,24 @@ The secret key is an api client enabled secret key and can be obtained from the
330
333
  If testing against a local version of DIALS you need to specify the BASE_URL:
331
334
 
332
335
  ```bash
333
- SECRET_KEY=... BASE_URl=http://localhost:8000 pytest tests
336
+ SECRET_KEY=... BASE_URL=http://localhost:8000 pytest tests --cov=cmsdials --cov-report=xml --cov-report=term --cov-report=html
337
+ ```
338
+
339
+ ### Tox
340
+
341
+ Tox is pre-configured in `pyproject.toml`, so you can run the following to test against multiple python versions locally:
342
+
343
+ ```bash
344
+ SECRET_KEY=... poetry run tox
334
345
  ```
335
346
 
347
+ **[asdf](https://asdf-vm.com/) users**
348
+
349
+ tox requires multiple versions of Python to be installed. Using `asdf`, you have multiple versions installed, but they aren’t normally exposed to the current shell. You can use the following command to expose multiple versions of Python in the current directory:
350
+
351
+ ```bash
352
+ asdf set python 3.12.9 3.11.10 3.10.13 3.9.19
353
+ ```
354
+
355
+ This will use `3.12.9` by default (if you just run `python`), but it will also put `python3.11`, `python3.10` and `python3.9` symlinks in your path so you can run those too (which is exactly what tox is looking for).
356
+
@@ -1,3 +1,7 @@
1
+ ![Build Status](https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py/badges/dev/pipeline.svg)
2
+ ![Coverage](https://gitlab.cern.ch/cms-dqmdc/libraries/dials-py/badges/dev/coverage.svg)
3
+ [![PyPI version](https://badge.fury.io/py/cmsdials.png)](https://badge.fury.io/py/cmsdials)
4
+
1
5
  # dials-py
2
6
 
3
7
  The Python api client interface to DIALS service.
@@ -294,7 +298,7 @@ dials.h2d.list_all(LumisectionHistogram2DFilters(me__regex="EEOT digi occupancy
294
298
  The repository has some tests written to make sure DIALS responses are compatible with pydantic metaclasses, you can use pytest to run all tests but you need to specify a secret key to authenticate non-interactively against DIALS api:
295
299
 
296
300
  ```bash
297
- SECRET_KEY=... pytest tests
301
+ SECRET_KEY=... pytest tests --cov=cmsdials --cov-report=xml --cov-report=term --cov-report=html
298
302
  ```
299
303
 
300
304
  The secret key is an api client enabled secret key and can be obtained from the applications portal, any api client secret key whitelisted in DIALS can be used. The interactive authentication flow should be tested manually, an example for this can be found in [this line](/tests/integration/test_auth_client.py#L33).
@@ -302,5 +306,23 @@ The secret key is an api client enabled secret key and can be obtained from the
302
306
  If testing against a local version of DIALS you need to specify the BASE_URL:
303
307
 
304
308
  ```bash
305
- SECRET_KEY=... BASE_URl=http://localhost:8000 pytest tests
309
+ SECRET_KEY=... BASE_URL=http://localhost:8000 pytest tests --cov=cmsdials --cov-report=xml --cov-report=term --cov-report=html
310
+ ```
311
+
312
+ ### Tox
313
+
314
+ Tox is pre-configured in `pyproject.toml`, so you can run the following to test against multiple python versions locally:
315
+
316
+ ```bash
317
+ SECRET_KEY=... poetry run tox
306
318
  ```
319
+
320
+ **[asdf](https://asdf-vm.com/) users**
321
+
322
+ tox requires multiple versions of Python to be installed. Using `asdf`, you have multiple versions installed, but they aren’t normally exposed to the current shell. You can use the following command to expose multiple versions of Python in the current directory:
323
+
324
+ ```bash
325
+ asdf set python 3.12.9 3.11.10 3.10.13 3.9.19
326
+ ```
327
+
328
+ This will use `3.12.9` by default (if you just run `python`), but it will also put `python3.11`, `python3.10` and `python3.9` symlinks in your path so you can run those too (which is exactly what tox is looking for).
@@ -0,0 +1,5 @@
1
+ from ._version import __version__
2
+ from .cmsdials import Dials
3
+
4
+
5
+ __all__ = ["__version__", "Dials"]
@@ -0,0 +1 @@
1
+ __version__ = "1.7.0"
@@ -126,7 +126,7 @@ class Credentials(BaseCredentials):
126
126
  def cache_credentials(self) -> None:
127
127
  fpath = self._handle_creds_filepath(self.cache_dir)
128
128
  with open(fpath, "w") as filebuffer:
129
- json.dump(self._token.dict(), filebuffer, cls=TokenEncoder)
129
+ json.dump(self._token.model_dump(), filebuffer, cls=TokenEncoder)
130
130
 
131
131
  def refresh(self) -> None:
132
132
  token: Token = self.client.refresh_token(self.token_type, self.token, self.refresh_token)
@@ -25,6 +25,7 @@ class AuthClient(BaseAPIClient):
25
25
  url=endpoint_url,
26
26
  headers={
27
27
  "accept": "application/json",
28
+ "User-Agent": self._build_user_agent()
28
29
  },
29
30
  timeout=self.default_timeout,
30
31
  )
@@ -39,6 +40,7 @@ class AuthClient(BaseAPIClient):
39
40
  headers={
40
41
  "accept": "application/json",
41
42
  "Content-Type": "application/json",
43
+ "User-Agent": self._build_user_agent()
42
44
  },
43
45
  json={"device_code": device_code},
44
46
  timeout=self.default_timeout,
@@ -65,6 +67,7 @@ class AuthClient(BaseAPIClient):
65
67
  "accept": "application/json",
66
68
  "Content-Type": "application/json",
67
69
  "Authorization": f"{token_type} {access_token}",
70
+ "User-Agent": self._build_user_agent()
68
71
  },
69
72
  json={"refresh_token": refresh_token},
70
73
  timeout=self.default_timeout,
@@ -23,7 +23,10 @@ class OMSProxyClient(BaseAPIClient):
23
23
  self.creds = creds
24
24
 
25
25
  def _build_headers(self) -> dict:
26
- base = {"accept": "application/json"}
26
+ base = {
27
+ "accept": "application/json",
28
+ "User-Agent": self._build_user_agent()
29
+ }
27
30
  self.creds.before_request(base)
28
31
  return base
29
32
 
@@ -1,13 +1,16 @@
1
+ import sys
1
2
  from importlib import util as importlib_util
2
3
  from traceback import format_exc
3
4
  from typing import Optional
4
- from urllib.parse import parse_qs, urlparse
5
5
  from warnings import warn
6
6
 
7
+ import requests
8
+ from pydantic import AnyUrl
7
9
  from requests import Response, Session
8
10
  from requests.adapters import DEFAULT_RETRIES, HTTPAdapter
9
11
  from requests.exceptions import HTTPError
10
12
 
13
+ from .._version import __version__
11
14
  from ..auth._base import BaseCredentials
12
15
  from ..utils.logger import logger
13
16
 
@@ -51,6 +54,12 @@ class BaseAPIClient:
51
54
  ret = s.get(*args, **kwargs)
52
55
  return ret
53
56
 
57
+ @staticmethod
58
+ def _build_user_agent():
59
+ py_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
60
+ req_version = requests.__version__
61
+ return f"dials-py/{__version__} (python/{py_version}, python-requests/{req_version})"
62
+
54
63
  @property
55
64
  def api_url(self):
56
65
  return self.base_url + self.route + self.version
@@ -75,7 +84,10 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
75
84
  self.workspace = workspace
76
85
 
77
86
  def _build_headers(self) -> dict:
78
- base = {"accept": "application/json"}
87
+ base = {
88
+ "accept": "application/json",
89
+ "User-Agent": self._build_user_agent()
90
+ }
79
91
  if self.workspace is not None:
80
92
  base["Workspace"] = self.workspace
81
93
  self.creds.before_request(base)
@@ -138,13 +150,13 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
138
150
  keep_failed: bool = False,
139
151
  resume_from=None,
140
152
  ):
141
- next_string: Optional[str] = None
153
+ next_string: Optional[AnyUrl] = None
142
154
  results = []
143
155
  is_last_page = False
144
156
 
145
157
  if resume_from is not None:
146
158
  results = resume_from.results
147
- next_string = resume_from.next
159
+ next_string: AnyUrl = resume_from.next
148
160
  if next_string is None and len(results):
149
161
  warn(
150
162
  "resume_from.next is None while resume_from.result is not empty, doing nothing.",
@@ -160,8 +172,8 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
160
172
  progress = tqdm(desc="Progress", total=1)
161
173
 
162
174
  while is_last_page is False:
163
- next_token = parse_qs(urlparse(next_string).query).get("next_token") if next_string else None
164
- curr_filters = self.filter_class(**filters.dict())
175
+ next_token = dict(next_string.query_params()).get("next_token") if next_string else None
176
+ curr_filters = self.filter_class(**filters.model_dump())
165
177
  curr_filters.next_token = next_token
166
178
  try:
167
179
  response = self.list(curr_filters, retries=retries)
@@ -186,7 +198,7 @@ class BaseAuthorizedAPIClient(BaseAPIClient):
186
198
  exc_formatted=exc_formatted,
187
199
  )
188
200
  results.extend(response.results)
189
- next_string = response.next
201
+ next_string: AnyUrl = response.next
190
202
  is_last_page = next_string is None
191
203
  total_pages += 1
192
204
  max_pages_reached = max_pages and total_pages >= max_pages
@@ -16,7 +16,7 @@ class OBaseModel(BaseModel):
16
16
  def cleandict(self):
17
17
  return {
18
18
  key: ",".join(str(v) for v in value) if isinstance(value, (list, tuple)) else value
19
- for key, value in self.dict().items()
19
+ for key, value in self.model_dump().items()
20
20
  if value is not None
21
21
  }
22
22
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cmsdials"
3
- version = "1.5.0"
3
+ version = "1.7.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"
@@ -19,17 +19,18 @@ packages = [
19
19
  [tool.poetry.dependencies]
20
20
  python = "^3.9"
21
21
  requests = "^2.31.0"
22
- pydantic = "<2, >=1"
23
- typing-extensions = "<4.6.0, >=3.6.6"
22
+ urllib3 = "^1.26.16"
23
+ pydantic = "^2.8.2"
24
24
  pandas = {version = ">=1.5.3", optional = true}
25
25
  tqdm = {version = ">=4.66.1", optional = true}
26
- urllib3 = "^2.2.3"
27
26
 
28
27
  [tool.poetry.group.dev.dependencies]
29
28
  pre-commit = "^3.6.2"
30
29
  ruff = "^0.4.2"
31
30
  notebook = "^7.1.3"
32
31
  pytest = "^8.2.0"
32
+ pytest-cov = "^6.0.0"
33
+ tox = "^4.24.1"
33
34
 
34
35
  [tool.poetry.extras]
35
36
  pandas = ["pandas"]
@@ -130,6 +131,19 @@ lines-after-imports = 2
130
131
  "**/{tests,docs}/*" = ["E402", "F403", "F405", "S", "N802"]
131
132
  "**/*test*.py" = ["E402", "F403", "F405", "S", "N802"]
132
133
 
134
+ [tool.poetry-dynamic-versioning]
135
+ enable = false
136
+
137
+ [tool.tox]
138
+ requires = ["tox>=4.24"]
139
+ env_list = ["py39", "py310", "py311", "py312"]
140
+
141
+ [tool.tox.env_run_base]
142
+ description = "Run test under {base_python}"
143
+ commands = [["pytest", "tests"]]
144
+ passenv = ["SECRET_KEY", "BASE_URL"]
145
+ allowlist_externals = ["pytest"]
146
+
133
147
  [build-system]
134
- requires = ["poetry-core"]
135
- build-backend = "poetry.core.masonry.api"
148
+ requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
149
+ build-backend = "poetry_dynamic_versioning.backend"
@@ -1,4 +0,0 @@
1
- from .cmsdials import Dials
2
-
3
-
4
- __all__ = ["Dials"]
File without changes
File without changes
File without changes