pyoncat 2.6__tar.gz → 2.7__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.
@@ -1,20 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyoncat
3
- Version: 2.6
3
+ Version: 2.7
4
4
  Summary: A Python Client for ONCat (the ORNL Neutron Catalog).
5
5
  Keywords: ornl,neutron,metadata,catalog
6
6
  Author: ONCat Support
7
7
  Author-email: oncat-support@ornl.gov
8
- Requires-Python: >=3.7,<4
8
+ Requires-Python: >=3.9,<4
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.7
11
- Classifier: Programming Language :: Python :: 3.8
12
10
  Classifier: Programming Language :: Python :: 3.9
13
11
  Classifier: Programming Language :: Python :: 3.10
14
12
  Classifier: Programming Language :: Python :: 3.11
15
13
  Classifier: Programming Language :: Python :: 3.12
16
14
  Classifier: Programming Language :: Python :: 3.13
17
15
  Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: 3.15
18
17
  Requires-Dist: requests
19
18
  Project-URL: Homepage, https://oncat.ornl.gov
20
19
  Description-Content-Type: text/markdown
@@ -59,6 +58,10 @@ Alternatively, a Conda package is available up on [Anaconda](https://anaconda.or
59
58
 
60
59
  To use the authenticated version of the API, you need to obtain credentials from an ONCat administrator. Please contact ONCat Support at [oncat-support@ornl.gov](mailto:oncat-support@ornl.gov) to request credentials.
61
60
 
61
+ ### Request headers
62
+
63
+ Every request PyONCat makes carries two headers: `User-Agent: pyoncat/<version> requests/<version> Python/<major.minor>`, naming PyONCat, the `requests` library, and the Python major.minor version, and `API-Client: v1 pyoncat/<version>`. They let server logs tell PyONCat traffic from other clients.
64
+
62
65
  ### Examples
63
66
 
64
67
  For usage examples, please refer to the API documentation at [oncat.ornl.gov](https://oncat.ornl.gov).
@@ -38,6 +38,10 @@ Alternatively, a Conda package is available up on [Anaconda](https://anaconda.or
38
38
 
39
39
  To use the authenticated version of the API, you need to obtain credentials from an ONCat administrator. Please contact ONCat Support at [oncat-support@ornl.gov](mailto:oncat-support@ornl.gov) to request credentials.
40
40
 
41
+ ### Request headers
42
+
43
+ Every request PyONCat makes carries two headers: `User-Agent: pyoncat/<version> requests/<version> Python/<major.minor>`, naming PyONCat, the `requests` library, and the Python major.minor version, and `API-Client: v1 pyoncat/<version>`. They let server logs tell PyONCat traffic from other clients.
44
+
41
45
  ### Examples
42
46
 
43
47
  For usage examples, please refer to the API documentation at [oncat.ornl.gov](https://oncat.ornl.gov).
@@ -34,7 +34,18 @@ from pyoncat.reduction import ReductionFileBuilder
34
34
  if TYPE_CHECKING:
35
35
  import threading
36
36
 
37
- __version__ = "2.6"
37
+ __version__ = "2.7"
38
+
39
+ # Sent on every request PyONCat makes, API calls and token requests alike,
40
+ # so server logs can tell PyONCat traffic from other clients.
41
+ _USER_AGENT = (
42
+ f"pyoncat/{__version__} requests/{requests.__version__} "
43
+ f"Python/{sys.version_info.major}.{sys.version_info.minor}"
44
+ )
45
+ _CLIENT_HEADERS = {
46
+ "User-Agent": _USER_AGENT,
47
+ "API-Client": f"v1 pyoncat/{__version__}",
48
+ }
38
49
 
39
50
  # Constant for autoreduction user
40
51
  AUTOREDUCTION_USER = "auto"
@@ -403,7 +414,6 @@ class ONCat:
403
414
  Task: Task
404
415
  Info: Info
405
416
  Cache: Cache
406
- Usage: Usage
407
417
  Template: Template
408
418
 
409
419
  def __init__(
@@ -525,14 +535,17 @@ class ONCat:
525
535
  timeout=self._timeout,
526
536
  )
527
537
  else:
538
+ auth_headers = (
539
+ {"Authorization": "Bearer " + self._api_token}
540
+ if self._api_token
541
+ else {}
542
+ )
528
543
  response = getattr(requests, method)(
529
544
  full_url,
530
545
  params=kwargs,
531
546
  json=data,
532
547
  verify=self._should_verify(),
533
- headers={"Authorization": "Bearer " + self._api_token}
534
- if self._api_token
535
- else None,
548
+ headers={**_CLIENT_HEADERS, **auth_headers},
536
549
  timeout=self._timeout,
537
550
  )
538
551
  try:
@@ -799,6 +812,7 @@ class ONCat:
799
812
  verify=self._should_verify(),
800
813
  timeout=post_timeout,
801
814
  headers={
815
+ **_CLIENT_HEADERS,
802
816
  "Content-Type": "application/x-www-form-urlencoded",
803
817
  "Accept": "application/json",
804
818
  },
@@ -975,6 +989,7 @@ class ONCat:
975
989
  ),
976
990
  scope=self._scopes,
977
991
  )
992
+ self._oauth_client.headers.update(_CLIENT_HEADERS)
978
993
  try:
979
994
  token = self._oauth_client.fetch_token(
980
995
  self._url + "/oauth/token",
@@ -1012,6 +1027,7 @@ class ONCat:
1012
1027
  client_secret=self._client_secret,
1013
1028
  )
1014
1029
  )
1030
+ initial_oauth_client.headers.update(_CLIENT_HEADERS)
1015
1031
 
1016
1032
  try:
1017
1033
  token = initial_oauth_client.fetch_token(
@@ -1060,6 +1076,7 @@ class ONCat:
1060
1076
  auto_refresh_kwargs=auto_refresh_kwargs,
1061
1077
  token_updater=self._save_token,
1062
1078
  )
1079
+ self._oauth_client.headers.update(_CLIENT_HEADERS)
1063
1080
 
1064
1081
  def _login_device_authorization(
1065
1082
  self,
@@ -1142,6 +1159,7 @@ class ONCat:
1142
1159
  verify=self._should_verify(),
1143
1160
  timeout=post_timeout,
1144
1161
  headers={
1162
+ **_CLIENT_HEADERS,
1145
1163
  "Content-Type": "application/x-www-form-urlencoded",
1146
1164
  "Accept": "application/json",
1147
1165
  },
@@ -1230,6 +1248,7 @@ class ONCat:
1230
1248
  verify=self._should_verify(),
1231
1249
  timeout=post_timeout,
1232
1250
  headers={
1251
+ **_CLIENT_HEADERS,
1233
1252
  "Content-Type": "application/x-www-form-urlencoded",
1234
1253
  "Accept": "application/json",
1235
1254
  },
@@ -1397,6 +1416,7 @@ class ONCat:
1397
1416
  },
1398
1417
  token_updater=self._save_token,
1399
1418
  )
1419
+ self._oauth_client.headers.update(_CLIENT_HEADERS)
1400
1420
 
1401
1421
 
1402
1422
  class ONCatObject:
@@ -1556,6 +1576,12 @@ ONCatRepresentation = ONCatObject
1556
1576
  ########################################################################
1557
1577
 
1558
1578
 
1579
+ # TODO: The REST documentation page derives the PyONCat class and method
1580
+ # in each code example from the resource's namespace and path, without
1581
+ # consulting this module. Where a resource has no class here, or the
1582
+ # class lacks the method, the example does not run. Decide how the
1583
+ # documentation should learn what this module provides or otherwise
1584
+ # resolve this mismatch.
1559
1585
  class _ONCatMixinMeta(type):
1560
1586
  REGISTERED_RESOURCES: ClassVar[list] = []
1561
1587
 
@@ -1719,7 +1745,7 @@ class Grouping(_ListableONCatMixin):
1719
1745
 
1720
1746
  class Mapping(_ListableONCatMixin):
1721
1747
  _RESOURCE_ENDPOINT = "mappings"
1722
- _NAMESPACE = "settings"
1748
+ _NAMESPACE = "option"
1723
1749
 
1724
1750
 
1725
1751
  class Proposal(_ListableONCatMixin):
@@ -1803,11 +1829,6 @@ class Cache(_UpdatableONCatMixin):
1803
1829
  _NAMESPACE = "admin"
1804
1830
 
1805
1831
 
1806
- class Usage(_ListableONCatMixin):
1807
- _RESOURCE_ENDPOINT = "usage"
1808
- _NAMESPACE = "admin"
1809
-
1810
-
1811
1832
  ########################################################################
1812
1833
 
1813
1834
 
@@ -1818,51 +1839,6 @@ class Template(
1818
1839
  _NAMESPACE = "settings"
1819
1840
 
1820
1841
 
1821
- ########################################################################
1822
- # Summary Resources
1823
- ########################################################################
1824
-
1825
-
1826
- class ExperimentSummary(_ONCatResource):
1827
- _RESOURCE_ENDPOINT = "experiments"
1828
- _NAMESPACE = "summary"
1829
-
1830
-
1831
- class GroupingSummary(_ONCatResource):
1832
- _RESOURCE_ENDPOINT = "groupings"
1833
- _NAMESPACE = "summary"
1834
-
1835
-
1836
- class InstrumentSummary(_ONCatResource):
1837
- _RESOURCE_ENDPOINT = "instruments"
1838
- _NAMESPACE = "summary"
1839
-
1840
-
1841
- class ReductionSummary(_ONCatResource):
1842
- _RESOURCE_ENDPOINT = "reductions"
1843
- _NAMESPACE = "summary"
1844
-
1845
-
1846
- class RunSummary(_ONCatResource):
1847
- _RESOURCE_ENDPOINT = "runs"
1848
- _NAMESPACE = "summary"
1849
-
1850
-
1851
- class SampleSummary(_ONCatResource):
1852
- _RESOURCE_ENDPOINT = "samples"
1853
- _NAMESPACE = "summary"
1854
-
1855
-
1856
- class ScanSummary(_ONCatResource):
1857
- _RESOURCE_ENDPOINT = "scans"
1858
- _NAMESPACE = "summary"
1859
-
1860
-
1861
- class SessionSummary(_ONCatResource):
1862
- _RESOURCE_ENDPOINT = "sessions"
1863
- _NAMESPACE = "summary"
1864
-
1865
-
1866
1842
  ########################################################################
1867
1843
  # Misc Tools
1868
1844
  ########################################################################
@@ -2099,22 +2075,22 @@ class DeviceAuthorizationError(PyONCatError):
2099
2075
  # (ADR-0097), spelled to read as outcomes the caller catches by reason --
2100
2076
  # Denied / Expired / Cancelled / Timeout. They subclass
2101
2077
  # `DeviceAuthorizationError`, so the suffixed base type still catches them.
2102
- class DeviceAuthorizationDenied(DeviceAuthorizationError): # noqa: N818 - public API name (ADR-0097)
2078
+ class DeviceAuthorizationDenied(DeviceAuthorizationError): # ruff: ignore[error-suffix-on-exception-name] - public API name (ADR-0097)
2103
2079
  """Raised when the user explicitly denied the sign-in request
2104
2080
  (the IdP returned `access_denied`, RFC 8628 §3.5)."""
2105
2081
 
2106
2082
 
2107
- class DeviceAuthorizationExpired(DeviceAuthorizationError): # noqa: N818 - public API name (ADR-0097)
2083
+ class DeviceAuthorizationExpired(DeviceAuthorizationError): # ruff: ignore[error-suffix-on-exception-name] - public API name (ADR-0097)
2108
2084
  """Raised when the device code expired before the user approved the
2109
2085
  sign-in (the IdP returned `expired_token`, RFC 8628 §3.5)."""
2110
2086
 
2111
2087
 
2112
- class DeviceAuthorizationCancelled(DeviceAuthorizationError): # noqa: N818 - public API name (ADR-0097)
2088
+ class DeviceAuthorizationCancelled(DeviceAuthorizationError): # ruff: ignore[error-suffix-on-exception-name] - public API name (ADR-0097)
2113
2089
  """Raised when the caller cancelled the sign-in in progress via the
2114
2090
  `cancel_event` passed to `login()`."""
2115
2091
 
2116
2092
 
2117
- class DeviceAuthorizationTimeout(DeviceAuthorizationError): # noqa: N818 - public API name (ADR-0097)
2093
+ class DeviceAuthorizationTimeout(DeviceAuthorizationError): # ruff: ignore[error-suffix-on-exception-name] - public API name (ADR-0097)
2118
2094
  """Raised when the sign-in did not complete before the overall
2119
2095
  caller deadline (`device_authorization_timeout`) or the server's own
2120
2096
  `expires_in`, whichever came first."""
@@ -566,7 +566,7 @@ class ReductionFileBuilder:
566
566
  """
567
567
  try:
568
568
  return self.write(path, overwrite)
569
- except Exception as e: # noqa: BLE001
569
+ except Exception as e: # ruff: ignore[blind-except]
570
570
  # Intentionally catch all exceptions - design requirement for
571
571
  # autoreduction scripts where cataloging failures should never
572
572
  # break the reduction workflow
@@ -7,7 +7,7 @@ build-backend = "poetry.masonry.api"
7
7
  # https://github.com/python-poetry/roadmap/issues/3
8
8
  [tool.poetry]
9
9
  name = "pyoncat"
10
- version = "2.6"
10
+ version = "2.7"
11
11
  description = "A Python Client for ONCat (the ORNL Neutron Catalog)."
12
12
  authors = ["ONCat Support <oncat-support@ornl.gov>"]
13
13
  readme = ["pyoncat/README.md", "pyoncat/LICENSE"]
@@ -21,7 +21,7 @@ packages = [
21
21
  ]
22
22
 
23
23
  [tool.poetry.dependencies]
24
- python = ">=3.7, <4"
24
+ python = ">=3.9, <4"
25
25
  requests = "*"
26
26
  oauthlib = { version = "*", optional = true }
27
27
  requests-oauthlib = { version = "*", optional = true }
File without changes