rucio 35.7.0__py3-none-any.whl → 37.0.0__py3-none-any.whl

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.

Potentially problematic release.


This version of rucio might be problematic. Click here for more details.

Files changed (266) hide show
  1. rucio/alembicrevision.py +1 -1
  2. rucio/{daemons/c3po/collectors → cli}/__init__.py +1 -0
  3. rucio/cli/account.py +216 -0
  4. rucio-35.7.0.data/scripts/rucio → rucio/cli/bin_legacy/rucio.py +769 -486
  5. rucio-35.7.0.data/scripts/rucio-admin → rucio/cli/bin_legacy/rucio_admin.py +476 -423
  6. rucio/cli/command.py +272 -0
  7. rucio/cli/config.py +72 -0
  8. rucio/cli/did.py +191 -0
  9. rucio/cli/download.py +128 -0
  10. rucio/cli/lifetime_exception.py +33 -0
  11. rucio/cli/replica.py +162 -0
  12. rucio/cli/rse.py +293 -0
  13. rucio/cli/rule.py +158 -0
  14. rucio/cli/scope.py +40 -0
  15. rucio/cli/subscription.py +73 -0
  16. rucio/cli/upload.py +60 -0
  17. rucio/cli/utils.py +226 -0
  18. rucio/client/accountclient.py +0 -1
  19. rucio/client/baseclient.py +33 -24
  20. rucio/client/client.py +45 -1
  21. rucio/client/didclient.py +5 -3
  22. rucio/client/downloadclient.py +6 -8
  23. rucio/client/replicaclient.py +0 -2
  24. rucio/client/richclient.py +317 -0
  25. rucio/client/rseclient.py +4 -4
  26. rucio/client/uploadclient.py +26 -12
  27. rucio/common/bittorrent.py +234 -0
  28. rucio/common/cache.py +66 -29
  29. rucio/common/checksum.py +168 -0
  30. rucio/common/client.py +122 -0
  31. rucio/common/config.py +22 -35
  32. rucio/common/constants.py +61 -3
  33. rucio/common/didtype.py +72 -24
  34. rucio/common/dumper/__init__.py +45 -38
  35. rucio/common/dumper/consistency.py +75 -30
  36. rucio/common/dumper/data_models.py +63 -19
  37. rucio/common/dumper/path_parsing.py +19 -8
  38. rucio/common/exception.py +65 -8
  39. rucio/common/extra.py +5 -10
  40. rucio/common/logging.py +13 -13
  41. rucio/common/pcache.py +8 -7
  42. rucio/common/plugins.py +59 -27
  43. rucio/common/policy.py +12 -3
  44. rucio/common/schema/__init__.py +84 -34
  45. rucio/common/schema/generic.py +0 -17
  46. rucio/common/schema/generic_multi_vo.py +0 -17
  47. rucio/common/test_rucio_server.py +12 -6
  48. rucio/common/types.py +132 -52
  49. rucio/common/utils.py +93 -643
  50. rucio/core/account_limit.py +14 -12
  51. rucio/core/authentication.py +2 -2
  52. rucio/core/config.py +23 -42
  53. rucio/core/credential.py +14 -15
  54. rucio/core/did.py +5 -1
  55. rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
  56. rucio/core/did_meta_plugins/filter_engine.py +62 -3
  57. rucio/core/did_meta_plugins/json_meta.py +2 -2
  58. rucio/core/did_meta_plugins/mongo_meta.py +43 -30
  59. rucio/core/did_meta_plugins/postgres_meta.py +75 -39
  60. rucio/core/identity.py +6 -5
  61. rucio/core/importer.py +4 -3
  62. rucio/core/lifetime_exception.py +2 -2
  63. rucio/core/lock.py +8 -7
  64. rucio/core/message.py +6 -0
  65. rucio/core/monitor.py +30 -29
  66. rucio/core/naming_convention.py +2 -2
  67. rucio/core/nongrid_trace.py +2 -2
  68. rucio/core/oidc.py +11 -9
  69. rucio/core/permission/__init__.py +79 -37
  70. rucio/core/permission/generic.py +1 -7
  71. rucio/core/permission/generic_multi_vo.py +1 -7
  72. rucio/core/quarantined_replica.py +4 -3
  73. rucio/core/replica.py +464 -139
  74. rucio/core/replica_sorter.py +55 -59
  75. rucio/core/request.py +34 -32
  76. rucio/core/rse.py +301 -97
  77. rucio/core/rse_counter.py +1 -2
  78. rucio/core/rse_expression_parser.py +7 -7
  79. rucio/core/rse_selector.py +9 -7
  80. rucio/core/rule.py +41 -40
  81. rucio/core/rule_grouping.py +42 -40
  82. rucio/core/scope.py +5 -4
  83. rucio/core/subscription.py +26 -28
  84. rucio/core/topology.py +11 -11
  85. rucio/core/trace.py +2 -2
  86. rucio/core/transfer.py +29 -15
  87. rucio/core/volatile_replica.py +4 -3
  88. rucio/daemons/atropos/atropos.py +1 -1
  89. rucio/daemons/auditor/__init__.py +2 -2
  90. rucio/daemons/auditor/srmdumps.py +6 -6
  91. rucio/daemons/automatix/automatix.py +32 -21
  92. rucio/daemons/badreplicas/necromancer.py +2 -2
  93. rucio/daemons/bb8/nuclei_background_rebalance.py +1 -1
  94. rucio/daemons/bb8/t2_background_rebalance.py +1 -1
  95. rucio/daemons/common.py +15 -25
  96. rucio/daemons/conveyor/finisher.py +2 -2
  97. rucio/daemons/conveyor/poller.py +18 -28
  98. rucio/daemons/conveyor/receiver.py +2 -2
  99. rucio/daemons/conveyor/stager.py +1 -0
  100. rucio/daemons/conveyor/submitter.py +3 -3
  101. rucio/daemons/hermes/hermes.py +91 -30
  102. rucio/daemons/judge/evaluator.py +2 -2
  103. rucio/daemons/oauthmanager/oauthmanager.py +3 -3
  104. rucio/daemons/reaper/dark_reaper.py +7 -3
  105. rucio/daemons/reaper/reaper.py +12 -16
  106. rucio/daemons/rsedecommissioner/config.py +1 -1
  107. rucio/daemons/rsedecommissioner/profiles/generic.py +5 -4
  108. rucio/daemons/rsedecommissioner/profiles/types.py +7 -6
  109. rucio/daemons/rsedecommissioner/rse_decommissioner.py +1 -1
  110. rucio/daemons/storage/consistency/actions.py +8 -6
  111. rucio/daemons/tracer/kronos.py +4 -4
  112. rucio/db/sqla/constants.py +5 -0
  113. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +4 -4
  114. rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
  115. rucio/db/sqla/models.py +157 -154
  116. rucio/db/sqla/session.py +58 -27
  117. rucio/db/sqla/types.py +2 -2
  118. rucio/db/sqla/util.py +2 -2
  119. rucio/gateway/account.py +18 -12
  120. rucio/gateway/account_limit.py +137 -60
  121. rucio/gateway/authentication.py +18 -12
  122. rucio/gateway/config.py +30 -20
  123. rucio/gateway/credential.py +9 -10
  124. rucio/gateway/did.py +70 -53
  125. rucio/gateway/dirac.py +6 -4
  126. rucio/gateway/exporter.py +3 -2
  127. rucio/gateway/heartbeat.py +6 -4
  128. rucio/gateway/identity.py +36 -51
  129. rucio/gateway/importer.py +3 -2
  130. rucio/gateway/lifetime_exception.py +3 -2
  131. rucio/gateway/meta_conventions.py +17 -6
  132. rucio/gateway/permission.py +4 -1
  133. rucio/gateway/quarantined_replica.py +3 -2
  134. rucio/gateway/replica.py +31 -22
  135. rucio/gateway/request.py +27 -18
  136. rucio/gateway/rse.py +69 -37
  137. rucio/gateway/rule.py +46 -26
  138. rucio/gateway/scope.py +3 -2
  139. rucio/gateway/subscription.py +14 -11
  140. rucio/gateway/vo.py +12 -8
  141. rucio/rse/__init__.py +3 -3
  142. rucio/rse/protocols/bittorrent.py +11 -1
  143. rucio/rse/protocols/cache.py +0 -11
  144. rucio/rse/protocols/dummy.py +0 -11
  145. rucio/rse/protocols/gfal.py +14 -9
  146. rucio/rse/protocols/globus.py +1 -1
  147. rucio/rse/protocols/http_cache.py +1 -1
  148. rucio/rse/protocols/posix.py +2 -2
  149. rucio/rse/protocols/protocol.py +84 -317
  150. rucio/rse/protocols/rclone.py +2 -1
  151. rucio/rse/protocols/rfio.py +10 -1
  152. rucio/rse/protocols/ssh.py +2 -1
  153. rucio/rse/protocols/storm.py +2 -13
  154. rucio/rse/protocols/webdav.py +74 -30
  155. rucio/rse/protocols/xrootd.py +2 -1
  156. rucio/rse/rsemanager.py +170 -53
  157. rucio/rse/translation.py +260 -0
  158. rucio/tests/common.py +23 -13
  159. rucio/tests/common_server.py +26 -9
  160. rucio/transfertool/bittorrent.py +15 -14
  161. rucio/transfertool/bittorrent_driver.py +5 -7
  162. rucio/transfertool/bittorrent_driver_qbittorrent.py +9 -8
  163. rucio/transfertool/fts3.py +20 -16
  164. rucio/transfertool/mock.py +2 -3
  165. rucio/vcsversion.py +4 -4
  166. rucio/version.py +7 -0
  167. rucio/web/rest/flaskapi/v1/accounts.py +17 -3
  168. rucio/web/rest/flaskapi/v1/auth.py +5 -5
  169. rucio/web/rest/flaskapi/v1/credentials.py +3 -2
  170. rucio/web/rest/flaskapi/v1/dids.py +21 -15
  171. rucio/web/rest/flaskapi/v1/identities.py +33 -9
  172. rucio/web/rest/flaskapi/v1/redirect.py +5 -4
  173. rucio/web/rest/flaskapi/v1/replicas.py +12 -8
  174. rucio/web/rest/flaskapi/v1/rses.py +15 -4
  175. rucio/web/rest/flaskapi/v1/traces.py +56 -19
  176. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/alembic.ini.template +1 -1
  177. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/alembic_offline.ini.template +1 -1
  178. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +3 -2
  179. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio.cfg.template +3 -19
  180. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +1 -18
  181. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/requirements.server.txt +97 -68
  182. rucio-37.0.0.data/scripts/rucio +133 -0
  183. rucio-37.0.0.data/scripts/rucio-admin +97 -0
  184. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-atropos +2 -2
  185. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-auditor +2 -1
  186. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-automatix +2 -2
  187. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-cache-client +17 -10
  188. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-receiver +1 -0
  189. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-kronos +1 -0
  190. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-minos +2 -2
  191. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-minos-temporary-expiration +2 -2
  192. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-necromancer +2 -2
  193. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-reaper +6 -6
  194. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-transmogrifier +2 -2
  195. rucio-37.0.0.dist-info/METADATA +92 -0
  196. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/RECORD +237 -243
  197. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/licenses/AUTHORS.rst +3 -0
  198. rucio/common/schema/atlas.py +0 -413
  199. rucio/common/schema/belleii.py +0 -408
  200. rucio/common/schema/domatpc.py +0 -401
  201. rucio/common/schema/escape.py +0 -426
  202. rucio/common/schema/icecube.py +0 -406
  203. rucio/core/permission/atlas.py +0 -1348
  204. rucio/core/permission/belleii.py +0 -1077
  205. rucio/core/permission/escape.py +0 -1078
  206. rucio/daemons/c3po/algorithms/__init__.py +0 -13
  207. rucio/daemons/c3po/algorithms/simple.py +0 -134
  208. rucio/daemons/c3po/algorithms/t2_free_space.py +0 -128
  209. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +0 -130
  210. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +0 -294
  211. rucio/daemons/c3po/c3po.py +0 -371
  212. rucio/daemons/c3po/collectors/agis.py +0 -108
  213. rucio/daemons/c3po/collectors/free_space.py +0 -81
  214. rucio/daemons/c3po/collectors/jedi_did.py +0 -57
  215. rucio/daemons/c3po/collectors/mock_did.py +0 -51
  216. rucio/daemons/c3po/collectors/network_metrics.py +0 -71
  217. rucio/daemons/c3po/collectors/workload.py +0 -112
  218. rucio/daemons/c3po/utils/__init__.py +0 -13
  219. rucio/daemons/c3po/utils/dataset_cache.py +0 -50
  220. rucio/daemons/c3po/utils/expiring_dataset_cache.py +0 -56
  221. rucio/daemons/c3po/utils/expiring_list.py +0 -62
  222. rucio/daemons/c3po/utils/popularity.py +0 -85
  223. rucio/daemons/c3po/utils/timeseries.py +0 -89
  224. rucio/rse/protocols/gsiftp.py +0 -92
  225. rucio-35.7.0.data/scripts/rucio-c3po +0 -85
  226. rucio-35.7.0.dist-info/METADATA +0 -72
  227. /rucio/{daemons/c3po → cli/bin_legacy}/__init__.py +0 -0
  228. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
  229. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
  230. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  231. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  232. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  233. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  234. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  235. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  236. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  237. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/bootstrap.py +0 -0
  238. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
  239. {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/reset_database.py +0 -0
  240. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-account +0 -0
  241. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-collection-replica +0 -0
  242. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-rse +0 -0
  243. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-bb8 +0 -0
  244. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-cache-consumer +0 -0
  245. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-finisher +0 -0
  246. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-poller +0 -0
  247. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-preparer +0 -0
  248. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-stager +0 -0
  249. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-submitter +0 -0
  250. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-throttler +0 -0
  251. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-dark-reaper +0 -0
  252. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-dumper +0 -0
  253. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-follower +0 -0
  254. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-hermes +0 -0
  255. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-cleaner +0 -0
  256. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-evaluator +0 -0
  257. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-injector +0 -0
  258. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-repairer +0 -0
  259. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-oauth-manager +0 -0
  260. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-replica-recoverer +0 -0
  261. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-rse-decommissioner +0 -0
  262. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-storage-consistency-actions +0 -0
  263. {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-undertaker +0 -0
  264. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/WHEEL +0 -0
  265. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/licenses/LICENSE +0 -0
  266. {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/top_level.txt +0 -0
rucio/core/topology.py CHANGED
@@ -17,7 +17,6 @@ import itertools
17
17
  import logging
18
18
  import threading
19
19
  import weakref
20
- from collections.abc import Callable, Iterable, Iterator
21
20
  from decimal import Decimal
22
21
  from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast
23
22
 
@@ -38,6 +37,7 @@ TE = TypeVar("TE", bound="Edge")
38
37
  ExpiringObjectCacheNewObject = TypeVar("ExpiringObjectCacheNewObject")
39
38
 
40
39
  if TYPE_CHECKING:
40
+ from collections.abc import Callable, Iterable, Iterator
41
41
  from typing import Protocol
42
42
 
43
43
  from sqlalchemy.orm import Session
@@ -63,7 +63,7 @@ INF = float('inf')
63
63
 
64
64
 
65
65
  class Node(RseData):
66
- def __init__(self, rse_id: str):
66
+ def __init__(self, rse_id: str) -> None:
67
67
  super().__init__(rse_id)
68
68
 
69
69
  self.in_edges = weakref.WeakKeyDictionary()
@@ -75,7 +75,7 @@ class Node(RseData):
75
75
 
76
76
 
77
77
  class Edge(Generic[TN]):
78
- def __init__(self, src_node: TN, dst_node: TN):
78
+ def __init__(self, src_node: TN, dst_node: TN) -> None:
79
79
  self._src_node = weakref.ref(src_node)
80
80
  self._dst_node = weakref.ref(dst_node)
81
81
 
@@ -123,11 +123,11 @@ class Topology(RseCollection, Generic[TN, TE]):
123
123
  """
124
124
  def __init__(
125
125
  self,
126
- rse_ids: Optional[Iterable[str]] = None,
126
+ rse_ids: Optional["Iterable[str]"] = None,
127
127
  ignore_availability: bool = False,
128
128
  node_cls: type[TN] = Node,
129
129
  edge_cls: type[TE] = Edge,
130
- ):
130
+ ) -> None:
131
131
  super().__init__(rse_ids=rse_ids, rse_data_cls=node_cls)
132
132
  self._edge_cls = edge_cls
133
133
  self._edges: dict[tuple[TN, TN], TE] = {}
@@ -284,7 +284,7 @@ class Topology(RseCollection, Generic[TN, TE]):
284
284
  @read_session
285
285
  def search_shortest_paths(
286
286
  self,
287
- src_nodes: Iterable[TN],
287
+ src_nodes: "Iterable[TN]",
288
288
  dst_node: TN,
289
289
  operation_src: str,
290
290
  operation_dest: str,
@@ -310,7 +310,7 @@ class Topology(RseCollection, Generic[TN, TE]):
310
310
  class _NodeStateProvider:
311
311
  _hop_penalty = self._hop_penalty
312
312
 
313
- def __init__(self, node: TN):
313
+ def __init__(self, node: TN) -> None:
314
314
  self.enabled: bool = True
315
315
  self.cost: _Number = 0
316
316
  if node != dst_node:
@@ -322,7 +322,7 @@ class Topology(RseCollection, Generic[TN, TE]):
322
322
  scheme_missmatch_found = {}
323
323
 
324
324
  class _EdgeStateProvider:
325
- def __init__(self, edge: TE):
325
+ def __init__(self, edge: TE) -> None:
326
326
  self.edge = edge
327
327
  self.chosen_scheme = {}
328
328
 
@@ -358,7 +358,7 @@ class Topology(RseCollection, Generic[TN, TE]):
358
358
  node_state_provider=_NodeStateProvider,
359
359
  edge_state_provider=_EdgeStateProvider):
360
360
  nh_node = edge_to_next_hop.dst_node
361
- edge_state = cast(_EdgeStateProvider, edge_state)
361
+ edge_state = cast("_EdgeStateProvider", edge_state)
362
362
  hop = {
363
363
  'source_rse': node,
364
364
  'dest_rse': nh_node,
@@ -433,8 +433,8 @@ class ExpiringObjectCache(Generic[ExpiringObjectCacheNewObject]):
433
433
  def __init__(
434
434
  self,
435
435
  ttl: int,
436
- new_obj_fnc: Callable[[], ExpiringObjectCacheNewObject]
437
- ):
436
+ new_obj_fnc: "Callable[[], ExpiringObjectCacheNewObject]"
437
+ ) -> None:
438
438
  self._lock = threading.Lock()
439
439
  self._object: Optional[ExpiringObjectCacheNewObject] = None
440
440
  self._creation_time: Optional[datetime.datetime] = None
rucio/core/trace.py CHANGED
@@ -26,7 +26,7 @@ from typing import TYPE_CHECKING, Any, Union, overload
26
26
  import stomp
27
27
  from jsonschema import Draft7Validator, ValidationError, validate
28
28
 
29
- from rucio.common.config import config_get, config_get_int
29
+ from rucio.common.config import config_get, config_get_int, config_get_list
30
30
  from rucio.common.exception import InvalidObject, TraceValidationSchemaNotFound
31
31
  from rucio.common.logging import rucio_log_formatter
32
32
  from rucio.common.schema.generic import TIME_ENTRY, UUID, IPv4orIPv6
@@ -70,7 +70,7 @@ ROTATING_LOGGER.addHandler(ROTATING_HANDLER)
70
70
 
71
71
  BROKERS_ALIAS, BROKERS_RESOLVED = [], []
72
72
  try:
73
- BROKERS_ALIAS = [b.strip() for b in config_get('trace', 'brokers').split(',')]
73
+ BROKERS_ALIAS = config_get_list('trace', 'brokers')
74
74
  except:
75
75
  raise Exception('Could not load brokers from configuration')
76
76
 
rucio/core/transfer.py CHANGED
@@ -38,7 +38,6 @@ from rucio.core import request as request_core
38
38
  from rucio.core.account import list_accounts
39
39
  from rucio.core.monitor import MetricManager
40
40
  from rucio.core.request import DirectTransfer, RequestSource, RequestWithSources, TransferDestination, transition_request_state
41
- from rucio.core.rse import RseData
42
41
  from rucio.core.rse_expression_parser import parse_expression
43
42
  from rucio.db.sqla import models
44
43
  from rucio.db.sqla.constants import DIDType, RequestState, RequestType, TransferLimitDirection
@@ -48,7 +47,6 @@ from rucio.transfertool.bittorrent import BittorrentTransfertool
48
47
  from rucio.transfertool.fts3 import FTS3Transfertool
49
48
  from rucio.transfertool.globus import GlobusTransferTool
50
49
  from rucio.transfertool.mock import MockTransfertool
51
- from rucio.transfertool.transfertool import TransferStatusReport, Transfertool
52
50
 
53
51
  if TYPE_CHECKING:
54
52
  from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
@@ -56,9 +54,11 @@ if TYPE_CHECKING:
56
54
 
57
55
  from sqlalchemy.orm import Session
58
56
 
59
- from rucio.common.types import InternalAccount
57
+ from rucio.common.types import InternalAccount, LFNDict
58
+ from rucio.core.rse import RseData
60
59
  from rucio.core.topology import Topology
61
60
  from rucio.rse.protocols.protocol import RSEProtocol
61
+ from rucio.transfertool.transfertool import TransferStatusReport, Transfertool
62
62
 
63
63
  LoggerFunction = Callable[..., Any]
64
64
 
@@ -90,7 +90,7 @@ class ProtocolFactory:
90
90
  def __init__(self):
91
91
  self.protocols = {}
92
92
 
93
- def protocol(self, rse: RseData, scheme: "Optional[str]", operation: str):
93
+ def protocol(self, rse: 'RseData', scheme: "Optional[str]", operation: str):
94
94
  protocol_key = '%s_%s_%s' % (operation, rse.id, scheme)
95
95
  protocol = self.protocols.get(protocol_key)
96
96
  if not protocol:
@@ -210,7 +210,12 @@ class DirectTransferImplementation(DirectTransfer):
210
210
  # Compute the source URL
211
211
  source_sign_url = src.rse.attributes.get(RseAttr.SIGN_URL, None)
212
212
  dest_sign_url = dst.rse.attributes.get(RseAttr.SIGN_URL, None)
213
- source_url = list(protocol.lfns2pfns(lfns={'scope': rws.scope.external, 'name': rws.name, 'path': src.file_path}).values())[0]
213
+ lfn: "LFNDict" = {
214
+ 'scope': rws.scope.external, # type: ignore (scope.external might be None)
215
+ 'name': rws.name,
216
+ 'path': src.file_path
217
+ }
218
+ source_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
214
219
  source_url = cls.__rewrite_source_url(source_url, source_sign_url=source_sign_url, dest_sign_url=dest_sign_url, source_scheme=src.scheme)
215
220
  return source_url
216
221
 
@@ -223,7 +228,11 @@ class DirectTransferImplementation(DirectTransfer):
223
228
  protocol = protocol_factory.protocol(dst.rse, dst.scheme, operation)
224
229
 
225
230
  if dst.rse.info['deterministic']:
226
- dest_url = list(protocol.lfns2pfns(lfns={'scope': rws.scope.external, 'name': rws.name}).values())[0]
231
+ lfn: "LFNDict" = {
232
+ 'scope': rws.scope.external, # type: ignore (scope.external might be None)
233
+ 'name': rws.name
234
+ }
235
+ dest_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
227
236
  else:
228
237
  # compute dest url in case of non deterministic
229
238
  # naming convention, etc.
@@ -236,7 +245,12 @@ class DirectTransferImplementation(DirectTransfer):
236
245
  if rws.retry_count or rws.activity == 'Recovery':
237
246
  dest_path = '%s_%i' % (dest_path, int(time.time()))
238
247
 
239
- dest_url = list(protocol.lfns2pfns(lfns={'scope': rws.scope.external, 'name': rws.name, 'path': dest_path}).values())[0]
248
+ lfn: "LFNDict" = {
249
+ 'scope': rws.scope.external, # type: ignore (scope.external might be None)
250
+ 'name': rws.name,
251
+ 'path': dest_path
252
+ }
253
+ dest_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
240
254
 
241
255
  dest_sign_url = dst.rse.attributes.get(RseAttr.SIGN_URL, None)
242
256
  dest_url = cls.__rewrite_dest_url(dest_url, dest_sign_url=dest_sign_url)
@@ -498,7 +512,7 @@ def set_transfers_state(
498
512
 
499
513
  @transactional_session
500
514
  def update_transfer_state(
501
- tt_status_report: TransferStatusReport,
515
+ tt_status_report: 'TransferStatusReport',
502
516
  stats_manager: request_core.TransferStatsManager,
503
517
  *,
504
518
  session: "Session",
@@ -744,7 +758,7 @@ def _create_stagein_definitions(
744
758
  """
745
759
  transfers_by_source = {
746
760
  source.rse: [
747
- cast(DirectTransfer, StageinTransferImplementation(
761
+ cast('DirectTransfer', StageinTransferImplementation(
748
762
  source=RequestSource(
749
763
  rse=source.rse,
750
764
  file_path=source.file_path,
@@ -973,7 +987,7 @@ class EnforceSourceRSEExpression(SourceFilterStrategy):
973
987
  return self._RankingContext(self, rws, allowed_source_rses)
974
988
 
975
989
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
976
- ctx = cast(EnforceSourceRSEExpression._RankingContext, ctx)
990
+ ctx = cast('EnforceSourceRSEExpression._RankingContext', ctx)
977
991
  if ctx.allowed_source_rses is not None and source.rse.id not in ctx.allowed_source_rses:
978
992
  return SKIP_SOURCE
979
993
 
@@ -1049,7 +1063,7 @@ class PathDistance(SourceRankingStrategy):
1049
1063
  return PathDistance._RankingContext(self, rws, paths_for_rws)
1050
1064
 
1051
1065
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1052
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1066
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1053
1067
  if not path:
1054
1068
  return SKIP_SOURCE
1055
1069
  return path[0].src.distance
@@ -1057,7 +1071,7 @@ class PathDistance(SourceRankingStrategy):
1057
1071
 
1058
1072
  class PreferSingleHop(PathDistance):
1059
1073
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1060
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1074
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1061
1075
  if not path:
1062
1076
  return SKIP_SOURCE
1063
1077
  return int(len(path) > 1)
@@ -1097,7 +1111,7 @@ class FailureRate(SourceRankingStrategy):
1097
1111
  self.source_stats.setdefault(stat['src_rse_id'], self._FailureRateStat()).incorporate_stat(stat)
1098
1112
 
1099
1113
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1100
- failure_rate = cast(FailureRate, ctx.strategy).source_stats.get(source.rse.id, self._FailureRateStat()).get_failure_rate()
1114
+ failure_rate = cast('FailureRate', ctx.strategy).source_stats.get(source.rse.id, self._FailureRateStat()).get_failure_rate()
1101
1115
  return failure_rate
1102
1116
 
1103
1117
 
@@ -1105,7 +1119,7 @@ class SkipSchemeMissmatch(PathDistance):
1105
1119
  filter_only = True
1106
1120
 
1107
1121
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1108
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1122
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1109
1123
  # path == None means that there is no path;
1110
1124
  # path == [] means that a path exists (according to distances) but cannot be used (scheme mismatch)
1111
1125
  if path is not None and not path:
@@ -1117,7 +1131,7 @@ class SkipIntermediateTape(PathDistance):
1117
1131
 
1118
1132
  def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
1119
1133
  # Discard multihop transfers which contain a tape source as an intermediate hop
1120
- path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
1134
+ path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
1121
1135
  if path and any(transfer.src.rse.is_tape_or_staging_required() for transfer in path[1:]):
1122
1136
  return SKIP_SOURCE
1123
1137
 
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from collections.abc import Iterable
16
15
  from datetime import datetime
17
16
  from typing import TYPE_CHECKING, Any
18
17
 
@@ -26,11 +25,13 @@ from rucio.db.sqla.constants import ReplicaState
26
25
  from rucio.db.sqla.session import transactional_session
27
26
 
28
27
  if TYPE_CHECKING:
28
+ from collections.abc import Iterable
29
+
29
30
  from sqlalchemy.orm import Session
30
31
 
31
32
 
32
33
  @transactional_session
33
- def add_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, session: "Session") -> None:
34
+ def add_volatile_replicas(rse_id: str, replicas: "Iterable[dict[str, Any]]", *, session: "Session") -> None:
34
35
  """
35
36
  Bulk add volatile replicas.
36
37
 
@@ -112,7 +113,7 @@ def add_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, se
112
113
 
113
114
 
114
115
  @transactional_session
115
- def delete_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, session: "Session") -> None:
116
+ def delete_volatile_replicas(rse_id: str, replicas: "Iterable[dict[str, Any]]", *, session: "Session") -> None:
116
117
  """
117
118
  Bulk delete volatile replicas.
118
119
 
@@ -81,7 +81,7 @@ def atropos(
81
81
 
82
82
  def run_once(
83
83
  heartbeat_handler: 'HeartbeatHandler',
84
- activity: None, # NOQA, pylint: disable=W0613
84
+ activity: None, # NOQA: ARG001
85
85
  date_check: datetime.datetime,
86
86
  dry_run: bool,
87
87
  grace_period: int,
@@ -16,9 +16,9 @@ import bz2
16
16
  import glob
17
17
  import logging
18
18
  import os
19
- import queue as Queue
20
19
  import select
21
20
  from datetime import datetime, timedelta
21
+ from queue import Empty as EmptyQueue
22
22
  from typing import TYPE_CHECKING, Optional
23
23
 
24
24
  from rucio.common import config
@@ -238,7 +238,7 @@ def check(
238
238
  while not terminate.is_set():
239
239
  try:
240
240
  rse, attempts = queue.get(timeout=30)
241
- except Queue.Empty:
241
+ except EmptyQueue:
242
242
  continue
243
243
  start = datetime.now()
244
244
  try:
@@ -12,15 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import configparser as ConfigParser
16
15
  import datetime
17
16
  import glob
18
17
  import hashlib
19
- import html.parser as HTMLParser
20
18
  import logging
21
19
  import operator
22
20
  import os
23
21
  import re
22
+ from configparser import RawConfigParser
23
+ from html.parser import HTMLParser
24
24
  from typing import IO, TYPE_CHECKING, Any, Optional
25
25
 
26
26
  import gfal2
@@ -49,7 +49,7 @@ __DUMPERCONFIGDIRS = list(
49
49
  OBJECTSTORE_NUM_TRIES = 30
50
50
 
51
51
 
52
- class Parser(ConfigParser.RawConfigParser):
52
+ class Parser(RawConfigParser):
53
53
  '''
54
54
  RawConfigParser subclass that doesn't modify the the name of the options
55
55
  and removes any quotes around the string values.
@@ -137,7 +137,7 @@ def gfal_links(base_url: str) -> list[str]:
137
137
  return ['/'.join((base_url, f)) for f in ctxt.listdir(str(base_url))]
138
138
 
139
139
 
140
- class _LinkCollector(HTMLParser.HTMLParser):
140
+ class _LinkCollector(HTMLParser):
141
141
  def __init__(self):
142
142
  super(_LinkCollector, self).__init__()
143
143
  self.links = []
@@ -244,7 +244,7 @@ def parse_configuration(conf_dirs: Optional[list[str]] = None) -> Parser:
244
244
 
245
245
  def download_rse_dump(
246
246
  rse: str,
247
- configuration: ConfigParser.RawConfigParser,
247
+ configuration: RawConfigParser,
248
248
  date: Optional[datetime.datetime] = None,
249
249
  destdir: str = DUMPS_CACHE_DIR
250
250
  ) -> tuple[str, datetime.datetime]:
@@ -331,7 +331,7 @@ def download_rse_dump(
331
331
 
332
332
  def generate_url(
333
333
  rse: str,
334
- config: ConfigParser.RawConfigParser
334
+ config: RawConfigParser
335
335
  ) -> tuple[str, str]:
336
336
  '''
337
337
  :param rse: Name of the endpoint.
@@ -28,7 +28,7 @@ import rucio.db.sqla.util
28
28
  from rucio.client import Client
29
29
  from rucio.client.uploadclient import UploadClient
30
30
  from rucio.common import exception
31
- from rucio.common.config import config_get, config_get_bool, config_get_int
31
+ from rucio.common.config import config_get, config_get_bool, config_get_int, config_get_list
32
32
  from rucio.common.logging import setup_logging
33
33
  from rucio.common.stopwatch import Stopwatch
34
34
  from rucio.common.types import InternalScope, LoggerFunction
@@ -149,18 +149,14 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
149
149
 
150
150
  _, _, logger = heartbeat_handler.live()
151
151
  try:
152
- rses = [
153
- s.strip() for s in config_get("automatix", "rses").split(",")
154
- ] # TODO use config_get_list
152
+ rses = config_get_list("automatix", "rses")
155
153
  except (NoOptionError, NoSectionError, RuntimeError):
156
154
  logging.log(
157
155
  logging.ERROR,
158
156
  "Option rses not found in automatix section. Trying the legacy sites option",
159
157
  )
160
158
  try:
161
- rses = [
162
- s.strip() for s in config_get("automatix", "sites").split(",")
163
- ] # TODO use config_get_list
159
+ rses = config_get_list("automatix", "sites")
164
160
  logging.log(
165
161
  logging.WARNING,
166
162
  "Option sites found in automatix section. This option will be deprecated soon. Please update your config to use rses.",
@@ -190,6 +186,8 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
190
186
  logger(logging.DEBUG, "Probabilities %s", probabilities)
191
187
 
192
188
  cycle_stopwatch = Stopwatch()
189
+ successes = []
190
+ failures = []
193
191
  for rse in rses:
194
192
  stopwatch = Stopwatch()
195
193
  _, _, logger = heartbeat_handler.live()
@@ -239,24 +237,37 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
239
237
  file_["dataset_meta"]["lifetime"] = dataset_lifetime
240
238
  files.append(file_)
241
239
  logger(logging.INFO, "Upload %s:%s to %s", scope, dsn, rse)
242
- upload_client = UploadClient(client)
243
- ret = upload_client.upload(files)
244
- if ret == 0:
245
- logger(logging.INFO, "%s successfully registered" % dsn)
246
- METRICS.counter(name="addnewdataset.done").inc()
247
- METRICS.counter(name="addnewfile.done").inc(nbfiles)
248
- METRICS.timer(name='datasetinjection').observe(stopwatch.elapsed)
249
- else:
250
- logger(logging.INFO, "Error uploading files")
251
- for physical_fname in physical_fnames:
252
- remove(physical_fname)
253
- rmdir(tmpdir)
240
+ try:
241
+ upload_client = UploadClient(client)
242
+ ret = upload_client.upload(files)
243
+ if ret == 0:
244
+ logger(logging.INFO, "%s successfully registered on %s", dsn, rse)
245
+ METRICS.counter(name="addnewdataset.done").inc()
246
+ METRICS.counter(name="addnewfile.done").inc(nbfiles)
247
+ METRICS.timer(name='datasetinjection').observe(stopwatch.elapsed)
248
+ successes.append(rse)
249
+ else:
250
+ logger(logging.INFO, "Error uploading files")
251
+ failures.append(rse)
252
+ except Exception as error:
253
+ logger(logging.ERROR, "Error uploading files on %s: %s", rse, str(error))
254
+ failures.append(rse)
255
+ finally:
256
+ for physical_fname in physical_fnames:
257
+ remove(physical_fname)
258
+ rmdir(tmpdir)
254
259
  logger(
255
260
  logging.INFO,
256
- "It took %f seconds to upload one dataset on %s",
261
+ "It took %f seconds to upload datasets on %s RSEs: %s",
257
262
  cycle_stopwatch.elapsed,
258
- str(rses),
263
+ len(successes),
264
+ str(successes),
259
265
  )
266
+ if failures:
267
+ logger(
268
+ logging.WARNING,
269
+ "Datasets could not be uploaded on %s RSEs: %s", len(failures), str(failures),
270
+ )
260
271
  return True
261
272
 
262
273
 
@@ -25,7 +25,7 @@ from sqlalchemy.exc import DatabaseError
25
25
 
26
26
  import rucio.db.sqla.util
27
27
  from rucio.common import exception
28
- from rucio.common.cache import make_region_memcached
28
+ from rucio.common.cache import MemcacheRegion
29
29
  from rucio.common.config import config_get_int
30
30
  from rucio.common.exception import DatabaseException
31
31
  from rucio.common.logging import setup_logging
@@ -41,7 +41,7 @@ if TYPE_CHECKING:
41
41
 
42
42
  graceful_stop = threading.Event()
43
43
  METRICS = MetricManager(module=__name__)
44
- REGION = make_region_memcached(expiration_time=config_get_int('necromancer', 'cache_time', False, 600))
44
+ REGION = MemcacheRegion(expiration_time=config_get_int('necromancer', 'cache_time', False, 600))
45
45
  DAEMON_NAME = 'necromancer'
46
46
 
47
47
 
@@ -61,7 +61,7 @@ total_total = 0
61
61
  global_ratio = float(0)
62
62
  for rse in rses:
63
63
  site_name = get_rse_attribute(rse['id'], RseAttr.SITE)
64
- rse['groupdisk'] = group_space(site_name)
64
+ rse['groupdisk'] = group_space(site_name) # type: ignore (site_name could be None)
65
65
  rse['primary'] = get_rse_usage(rse_id=rse['id'], source='rucio')[0]['used'] - get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
66
66
  rse['primary'] += rse['groupdisk']
67
67
  rse['secondary'] = get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
@@ -61,7 +61,7 @@ total_total = 0
61
61
  global_ratio = float(0)
62
62
  for rse in rses:
63
63
  site_name = get_rse_attribute(rse['id'], RseAttr.SITE)
64
- rse['groupdisk'] = group_space(site_name)
64
+ rse['groupdisk'] = group_space(site_name) # type: ignore (site_name could be None)
65
65
  rse['primary'] = get_rse_usage(rse_id=rse['id'], source='rucio')[0]['used'] - get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
66
66
  rse['primary'] += rse['groupdisk']
67
67
  rse['secondary'] = get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
rucio/daemons/common.py CHANGED
@@ -20,7 +20,6 @@ import queue
20
20
  import socket
21
21
  import threading
22
22
  import time
23
- from collections.abc import Callable, Generator, Iterator, Sequence
24
23
  from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union
25
24
 
26
25
  from rucio.common.logging import formatted_logger
@@ -29,6 +28,8 @@ from rucio.core import heartbeat as heartbeat_core
29
28
  from rucio.core.monitor import MetricManager
30
29
 
31
30
  if TYPE_CHECKING:
31
+ from collections.abc import Callable, Generator, Iterator, Sequence
32
+
32
33
  from rucio.common.types import LoggerFunction
33
34
 
34
35
  T = TypeVar('T')
@@ -85,7 +86,7 @@ class HeartbeatHandler:
85
86
  self,
86
87
  force_renew: bool = False,
87
88
  payload: Optional[str] = None
88
- ) -> tuple[int, int, Callable]:
89
+ ) -> tuple[int, int, 'Callable']:
89
90
  """
90
91
  :return: a tuple: <the number of the current worker>, <total number of workers>, <decorated logger>
91
92
  """
@@ -115,9 +116,9 @@ class HeartbeatHandler:
115
116
  def _activity_looper(
116
117
  once: bool,
117
118
  sleep_time: int,
118
- activities: Optional[Sequence[str]],
119
+ activities: Optional['Sequence[str]'],
119
120
  heartbeat_handler: HeartbeatHandler,
120
- ) -> Generator[tuple[str, float], tuple[float, bool], None]:
121
+ ) -> 'Generator[tuple[str, float], tuple[float, bool], None]':
121
122
  """
122
123
  Generator which loops (either once, or indefinitely) over all activities while ensuring that `sleep_time`
123
124
  passes between handling twice the same activity.
@@ -164,7 +165,7 @@ def _activity_looper(
164
165
  if not once:
165
166
  if must_sleep:
166
167
  time_diff = time.time() - actual_exe_time
167
- time_to_sleep = max(1, sleep_time - time_diff)
168
+ time_to_sleep = max(1.0, sleep_time - time_diff)
168
169
  activity_next_exe_time[activity] = time.time() + time_to_sleep
169
170
  else:
170
171
  activity_next_exe_time[activity] = time.time() + 1
@@ -176,19 +177,8 @@ def db_workqueue(
176
177
  executable: str,
177
178
  partition_wait_time: int,
178
179
  sleep_time: int,
179
- activities: Optional[Sequence[str]] = None,
180
- ) -> Callable[
181
- [
182
- Callable[
183
- ...,
184
- Union[bool, tuple[bool, T], None]
185
- ]
186
- ],
187
- Callable[
188
- [],
189
- Iterator[Union[T, None]]
190
- ]
191
- ]:
180
+ activities: Optional['Sequence[str]'] = None,
181
+ ) -> 'Callable[[Callable[..., Union[bool, tuple[bool, T], None]]], Callable[[], Iterator[Union[T, None]]]]':
192
182
  """
193
183
  Used to wrap a function for interacting with the database as a work queue: i.e. to select
194
184
  a set of rows and perform some work on those rows while ensuring that two instances running in parallel don't
@@ -203,10 +193,10 @@ def db_workqueue(
203
193
  :param activities: optional list of activities on which to work. The run_once_fnc will be called on activities one by one.
204
194
  """
205
195
 
206
- def _decorate(run_once_fnc: Callable[..., Optional[Union[bool, tuple[bool, T]]]]) -> Callable[[], Iterator[Optional[T]]]:
196
+ def _decorate(run_once_fnc: 'Callable[..., Optional[Union[bool, tuple[bool, T]]]]') -> 'Callable[[], Iterator[Optional[T]]]':
207
197
 
208
198
  @functools.wraps(run_once_fnc)
209
- def _generator() -> Iterator[T]:
199
+ def _generator() -> 'Iterator[T]':
210
200
 
211
201
  with HeartbeatHandler(executable=executable, renewal_interval=sleep_time - 1) as heartbeat_handler:
212
202
  logger = heartbeat_handler.logger
@@ -270,7 +260,7 @@ def run_daemon(
270
260
  executable: str,
271
261
  partition_wait_time: int,
272
262
  sleep_time: int,
273
- run_once_fnc: Callable[..., Optional[Union[bool, tuple[bool, Any]]]],
263
+ run_once_fnc: 'Callable[..., Optional[Union[bool, tuple[bool, Any]]]]',
274
264
  activities: Optional[list[str]] = None
275
265
  ) -> None:
276
266
  """
@@ -297,8 +287,8 @@ class ProducerConsumerDaemon(Generic[T]):
297
287
 
298
288
  def __init__(
299
289
  self,
300
- producers: Sequence[Callable[[], Iterator[T]]],
301
- consumers: Sequence[Callable[..., None]],
290
+ producers: 'Sequence[Callable[[], Iterator[T]]]',
291
+ consumers: 'Sequence[Callable[..., None]]',
302
292
  graceful_stop: threading.Event,
303
293
  logger: "LoggerFunction" = logging.log
304
294
  ):
@@ -314,7 +304,7 @@ class ProducerConsumerDaemon(Generic[T]):
314
304
 
315
305
  def _produce(
316
306
  self,
317
- it: Callable[[], Iterator[T]],
307
+ it: 'Callable[[], Iterator[T]]',
318
308
  wait_for_consumers: bool = False
319
309
  ) -> None:
320
310
  """
@@ -351,7 +341,7 @@ class ProducerConsumerDaemon(Generic[T]):
351
341
 
352
342
  def _consume(
353
343
  self,
354
- fnc: Callable[[T], Any]
344
+ fnc: 'Callable[[T], Any]'
355
345
  ) -> None:
356
346
  """
357
347
  Wait for elements to arrive via the queue and call the given function on each element.
@@ -29,7 +29,7 @@ from dogpile.cache.api import NoValue
29
29
  from sqlalchemy.exc import DatabaseError
30
30
 
31
31
  import rucio.db.sqla.util
32
- from rucio.common.cache import make_region_memcached
32
+ from rucio.common.cache import MemcacheRegion
33
33
  from rucio.common.config import config_get_bool, config_get_list
34
34
  from rucio.common.exception import DatabaseException, ReplicaNotFound, RequestNotFound, RSEProtocolNotSupported, UnsupportedOperation
35
35
  from rucio.common.logging import setup_logging
@@ -55,7 +55,7 @@ if TYPE_CHECKING:
55
55
 
56
56
  GRACEFUL_STOP = threading.Event()
57
57
 
58
- REGION = make_region_memcached(expiration_time=900)
58
+ REGION = MemcacheRegion(expiration_time=900)
59
59
  METRICS = MetricManager(module=__name__)
60
60
  DAEMON_NAME = 'conveyor-finisher'
61
61
  FAILED_DURING_SUBMISSION_DELAY = datetime.timedelta(minutes=120)