DIRAC 9.0.0a54__py3-none-any.whl → 9.0.7__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.
Files changed (166) hide show
  1. DIRAC/AccountingSystem/Client/AccountingCLI.py +0 -140
  2. DIRAC/AccountingSystem/Client/DataStoreClient.py +0 -13
  3. DIRAC/AccountingSystem/Client/Types/BaseAccountingType.py +0 -7
  4. DIRAC/AccountingSystem/ConfigTemplate.cfg +0 -5
  5. DIRAC/AccountingSystem/Service/DataStoreHandler.py +0 -72
  6. DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py +0 -9
  7. DIRAC/ConfigurationSystem/Client/Helpers/Registry.py +34 -32
  8. DIRAC/ConfigurationSystem/Client/Helpers/Resources.py +11 -43
  9. DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py +0 -16
  10. DIRAC/ConfigurationSystem/Client/LocalConfiguration.py +14 -8
  11. DIRAC/ConfigurationSystem/Client/PathFinder.py +47 -8
  12. DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py +4 -1
  13. DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +9 -2
  14. DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
  15. DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
  16. DIRAC/Core/DISET/ServiceReactor.py +11 -3
  17. DIRAC/Core/DISET/private/BaseClient.py +1 -2
  18. DIRAC/Core/DISET/private/Transports/M2SSLTransport.py +9 -7
  19. DIRAC/Core/Security/DiracX.py +12 -7
  20. DIRAC/Core/Security/IAMService.py +4 -3
  21. DIRAC/Core/Security/ProxyInfo.py +9 -5
  22. DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
  23. DIRAC/Core/Tornado/Client/ClientSelector.py +4 -1
  24. DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
  25. DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
  26. DIRAC/Core/Utilities/DErrno.py +5 -309
  27. DIRAC/Core/Utilities/Extensions.py +10 -1
  28. DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
  29. DIRAC/Core/Utilities/JDL.py +1 -195
  30. DIRAC/Core/Utilities/List.py +1 -124
  31. DIRAC/Core/Utilities/MySQL.py +101 -97
  32. DIRAC/Core/Utilities/Os.py +32 -1
  33. DIRAC/Core/Utilities/Platform.py +2 -107
  34. DIRAC/Core/Utilities/ReturnValues.py +7 -252
  35. DIRAC/Core/Utilities/StateMachine.py +12 -178
  36. DIRAC/Core/Utilities/TimeUtilities.py +10 -253
  37. DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
  38. DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
  39. DIRAC/Core/scripts/dirac_agent.py +1 -1
  40. DIRAC/Core/scripts/dirac_apptainer_exec.py +16 -7
  41. DIRAC/Core/scripts/dirac_platform.py +1 -92
  42. DIRAC/DataManagementSystem/Agent/FTS3Agent.py +8 -7
  43. DIRAC/DataManagementSystem/Agent/RequestOperations/RemoveFile.py +7 -6
  44. DIRAC/DataManagementSystem/Client/FTS3Job.py +71 -34
  45. DIRAC/DataManagementSystem/DB/FTS3DB.py +3 -0
  46. DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
  47. DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
  48. DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
  49. DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
  50. DIRAC/FrameworkSystem/Client/ComponentInstaller.py +4 -2
  51. DIRAC/FrameworkSystem/DB/ProxyDB.py +9 -5
  52. DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
  53. DIRAC/FrameworkSystem/Utilities/diracx.py +2 -74
  54. DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
  55. DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
  56. DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +1 -1
  57. DIRAC/Interfaces/API/Dirac.py +27 -13
  58. DIRAC/Interfaces/API/DiracAdmin.py +42 -7
  59. DIRAC/Interfaces/API/Job.py +1 -0
  60. DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +7 -1
  61. DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +7 -1
  62. DIRAC/Interfaces/scripts/dirac_wms_job_parameters.py +0 -1
  63. DIRAC/MonitoringSystem/Client/Types/WMSHistory.py +4 -0
  64. DIRAC/MonitoringSystem/Client/WebAppClient.py +26 -0
  65. DIRAC/MonitoringSystem/ConfigTemplate.cfg +9 -0
  66. DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -25
  67. DIRAC/MonitoringSystem/Service/MonitoringHandler.py +0 -33
  68. DIRAC/MonitoringSystem/Service/WebAppHandler.py +599 -0
  69. DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
  70. DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py +2 -3
  71. DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
  72. DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
  73. DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
  74. DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
  75. DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
  76. DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
  77. DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +18 -4
  78. DIRAC/Resources/Catalog/RucioFileCatalogClient.py +1 -1
  79. DIRAC/Resources/Computing/AREXComputingElement.py +19 -3
  80. DIRAC/Resources/Computing/BatchSystems/Condor.py +126 -108
  81. DIRAC/Resources/Computing/BatchSystems/SLURM.py +5 -1
  82. DIRAC/Resources/Computing/BatchSystems/test/Test_SLURM.py +46 -0
  83. DIRAC/Resources/Computing/HTCondorCEComputingElement.py +37 -43
  84. DIRAC/Resources/Computing/SingularityComputingElement.py +6 -1
  85. DIRAC/Resources/Computing/test/Test_HTCondorCEComputingElement.py +67 -49
  86. DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
  87. DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
  88. DIRAC/Resources/IdProvider/IdProviderFactory.py +11 -3
  89. DIRAC/Resources/Storage/StorageBase.py +4 -2
  90. DIRAC/Resources/Storage/StorageElement.py +4 -4
  91. DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
  92. DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
  93. DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +15 -15
  94. DIRAC/TransformationSystem/Client/Transformation.py +2 -1
  95. DIRAC/TransformationSystem/Client/TransformationClient.py +0 -7
  96. DIRAC/TransformationSystem/Client/Utilities.py +9 -0
  97. DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -336
  98. DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
  99. DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
  100. DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
  101. DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
  102. DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +1 -5
  103. DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +11 -7
  104. DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
  105. DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
  106. DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +10 -13
  107. DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
  108. DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
  109. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +2 -0
  110. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py +7 -9
  111. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
  112. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +8 -2
  113. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
  114. DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +7 -5
  115. DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
  116. DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
  117. DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
  118. DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
  119. DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py +25 -38
  120. DIRAC/WorkloadManagementSystem/Client/WMSClient.py +2 -3
  121. DIRAC/WorkloadManagementSystem/Client/test/Test_Client_DownloadInputData.py +29 -0
  122. DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg +4 -8
  123. DIRAC/WorkloadManagementSystem/DB/JobDB.py +40 -69
  124. DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
  125. DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
  126. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +3 -2
  127. DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +28 -39
  128. DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
  129. DIRAC/WorkloadManagementSystem/DB/tests/Test_JobDB.py +1 -1
  130. DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
  131. DIRAC/WorkloadManagementSystem/Executor/JobSanity.py +3 -3
  132. DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +2 -14
  133. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +14 -9
  134. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +36 -10
  135. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
  136. DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +33 -154
  137. DIRAC/WorkloadManagementSystem/Service/JobMonitoringHandler.py +5 -323
  138. DIRAC/WorkloadManagementSystem/Service/JobStateUpdateHandler.py +0 -16
  139. DIRAC/WorkloadManagementSystem/Service/PilotManagerHandler.py +6 -102
  140. DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +5 -51
  141. DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
  142. DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -199
  143. DIRAC/WorkloadManagementSystem/Utilities/JobParameters.py +65 -3
  144. DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +2 -64
  145. DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
  146. DIRAC/WorkloadManagementSystem/Utilities/PilotCStoJSONSynchronizer.py +73 -7
  147. DIRAC/WorkloadManagementSystem/Utilities/PilotWrapper.py +2 -0
  148. DIRAC/WorkloadManagementSystem/Utilities/RemoteRunner.py +16 -0
  149. DIRAC/WorkloadManagementSystem/Utilities/Utils.py +36 -1
  150. DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +15 -0
  151. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -5
  152. DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
  153. DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
  154. DIRAC/__init__.py +55 -54
  155. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/METADATA +6 -4
  156. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/RECORD +160 -160
  157. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
  158. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/entry_points.txt +0 -3
  159. DIRAC/Core/Utilities/test/Test_List.py +0 -150
  160. DIRAC/Core/Utilities/test/Test_Time.py +0 -88
  161. DIRAC/TransformationSystem/scripts/dirac_transformation_archive.py +0 -30
  162. DIRAC/TransformationSystem/scripts/dirac_transformation_clean.py +0 -30
  163. DIRAC/TransformationSystem/scripts/dirac_transformation_remove_output.py +0 -30
  164. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobManager.py +0 -58
  165. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/licenses/LICENSE +0 -0
  166. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/top_level.txt +0 -0
@@ -1,203 +1,9 @@
1
1
  """Transformation classes around the JDL format."""
2
2
 
3
- from diraccfg import CFG
4
- from pydantic import ValidationError
3
+ from DIRACCommon.Core.Utilities.JDL import * # noqa: F403,F401
5
4
 
6
- from DIRAC import S_OK, S_ERROR
7
- from DIRAC.Core.Utilities import List
8
- from DIRAC.Core.Utilities.ClassAd.ClassAdLight import ClassAd
9
5
  from DIRAC.WorkloadManagementSystem.Utilities.JobModel import BaseJobDescriptionModel
10
6
 
11
- ARGUMENTS = "Arguments"
12
- BANNED_SITES = "BannedSites"
13
- CPU_TIME = "CPUTime"
14
- EXECUTABLE = "Executable"
15
- EXECUTION_ENVIRONMENT = "ExecutionEnvironment"
16
- GRID_CE = "GridCE"
17
- INPUT_DATA = "InputData"
18
- INPUT_DATA_POLICY = "InputDataPolicy"
19
- INPUT_SANDBOX = "InputSandbox"
20
- JOB_CONFIG_ARGS = "JobConfigArgs"
21
- JOB_TYPE = "JobType"
22
- JOB_GROUP = "JobGroup"
23
- LOG_LEVEL = "LogLevel"
24
- NUMBER_OF_PROCESSORS = "NumberOfProcessors"
25
- MAX_NUMBER_OF_PROCESSORS = "MaxNumberOfProcessors"
26
- MIN_NUMBER_OF_PROCESSORS = "MinNumberOfProcessors"
27
- OUTPUT_DATA = "OutputData"
28
- OUTPUT_PATH = "OutputPath"
29
- OUTPUT_SE = "OutputSE"
30
- PLATFORM = "Platform"
31
- PRIORITY = "Priority"
32
- STD_ERROR = "StdError"
33
- STD_OUTPUT = "StdOutput"
34
- OUTPUT_SANDBOX = "OutputSandbox"
35
- JOB_NAME = "JobName"
36
- SITE = "Site"
37
- TAGS = "Tags"
38
-
39
- OWNER = "Owner"
40
- OWNER_GROUP = "OwnerGroup"
41
- VO = "VirtualOrganization"
42
-
43
- CREDENTIALS_FIELDS = {OWNER, OWNER_GROUP, VO}
44
-
45
-
46
- def loadJDLAsCFG(jdl):
47
- """
48
- Load a JDL as CFG
49
- """
50
-
51
- def cleanValue(value):
52
- value = value.strip()
53
- if value[0] == '"':
54
- entries = []
55
- iPos = 1
56
- current = ""
57
- state = "in"
58
- while iPos < len(value):
59
- if value[iPos] == '"':
60
- if state == "in":
61
- entries.append(current)
62
- current = ""
63
- state = "out"
64
- elif state == "out":
65
- current = current.strip()
66
- if current not in (",",):
67
- return S_ERROR("value seems a list but is not separated in commas")
68
- current = ""
69
- state = "in"
70
- else:
71
- current += value[iPos]
72
- iPos += 1
73
- if state == "in":
74
- return S_ERROR('value is opened with " but is not closed')
75
- return S_OK(", ".join(entries))
76
- else:
77
- return S_OK(value.replace('"', ""))
78
-
79
- def assignValue(key, value, cfg):
80
- key = key.strip()
81
- if len(key) == 0:
82
- return S_ERROR("Invalid key name")
83
- value = value.strip()
84
- if not value:
85
- return S_ERROR(f"No value for key {key}")
86
- if value[0] == "{":
87
- if value[-1] != "}":
88
- return S_ERROR("Value '%s' seems a list but does not end in '}'" % (value))
89
- valList = List.fromChar(value[1:-1])
90
- for i in range(len(valList)):
91
- result = cleanValue(valList[i])
92
- if not result["OK"]:
93
- return S_ERROR(f"Var {key} : {result['Message']}")
94
- valList[i] = result["Value"]
95
- if valList[i] is None:
96
- return S_ERROR(f"List value '{value}' seems invalid for item {i}")
97
- value = ", ".join(valList)
98
- else:
99
- result = cleanValue(value)
100
- if not result["OK"]:
101
- return S_ERROR(f"Var {key} : {result['Message']}")
102
- nV = result["Value"]
103
- if nV is None:
104
- return S_ERROR(f"Value '{value} seems invalid")
105
- value = nV
106
- cfg.setOption(key, value)
107
- return S_OK()
108
-
109
- if jdl[0] == "[":
110
- iPos = 1
111
- else:
112
- iPos = 0
113
- key = ""
114
- value = ""
115
- action = "key"
116
- insideLiteral = False
117
- cfg = CFG()
118
- while iPos < len(jdl):
119
- char = jdl[iPos]
120
- if char == ";" and not insideLiteral:
121
- if key.strip():
122
- result = assignValue(key, value, cfg)
123
- if not result["OK"]:
124
- return result
125
- key = ""
126
- value = ""
127
- action = "key"
128
- elif char == "[" and not insideLiteral:
129
- key = key.strip()
130
- if not key:
131
- return S_ERROR("Invalid key in JDL")
132
- if value.strip():
133
- return S_ERROR(f"Key {key} seems to have a value and open a sub JDL at the same time")
134
- result = loadJDLAsCFG(jdl[iPos:])
135
- if not result["OK"]:
136
- return result
137
- subCfg, subPos = result["Value"]
138
- cfg.createNewSection(key, contents=subCfg)
139
- key = ""
140
- value = ""
141
- action = "key"
142
- insideLiteral = False
143
- iPos += subPos
144
- elif char == "=" and not insideLiteral:
145
- if action == "key":
146
- action = "value"
147
- insideLiteral = False
148
- else:
149
- value += char
150
- elif char == "]" and not insideLiteral:
151
- key = key.strip()
152
- if len(key) > 0:
153
- result = assignValue(key, value, cfg)
154
- if not result["OK"]:
155
- return result
156
- return S_OK((cfg, iPos))
157
- else:
158
- if action == "key":
159
- key += char
160
- else:
161
- value += char
162
- if char == '"':
163
- insideLiteral = not insideLiteral
164
- iPos += 1
165
-
166
- return S_OK((cfg, iPos))
167
-
168
-
169
- def dumpCFGAsJDL(cfg, level=1, tab=" "):
170
- indent = tab * level
171
- contents = [f"{tab * (level - 1)}["]
172
- sections = cfg.listSections()
173
-
174
- for key in cfg:
175
- if key in sections:
176
- contents.append(f"{indent}{key} =")
177
- contents.append(f"{dumpCFGAsJDL(cfg[key], level + 1, tab)};")
178
- else:
179
- val = List.fromChar(cfg[key])
180
- # Some attributes are never lists
181
- if len(val) < 2 or key in [ARGUMENTS, EXECUTABLE, STD_OUTPUT, STD_ERROR]:
182
- value = cfg[key]
183
- try:
184
- try_value = float(value)
185
- contents.append(f"{tab * level}{key} = {value};")
186
- except Exception:
187
- contents.append(f'{tab * level}{key} = "{value}";')
188
- else:
189
- contents.append(f"{indent}{key} =")
190
- contents.append("%s{" % indent)
191
- for iPos in range(len(val)):
192
- try:
193
- value = float(val[iPos])
194
- except Exception:
195
- val[iPos] = f'"{val[iPos]}"'
196
- contents.append(",\n".join([f"{tab * (level + 1)}{value}" for value in val]))
197
- contents.append("%s};" % indent)
198
- contents.append(f"{tab * (level - 1)}]")
199
- return "\n".join(contents)
200
-
201
7
 
202
8
  def jdlToBaseJobDescriptionModel(classAd: ClassAd):
203
9
  """
@@ -1,124 +1 @@
1
- """Collection of DIRAC useful list related modules.
2
- By default on Error they return None.
3
- """
4
- import random
5
- import sys
6
- from typing import Any
7
-
8
-
9
- def uniqueElements(aList: list) -> list:
10
- """Utility to retrieve list of unique elements in a list (order is kept)."""
11
-
12
- # Use dict.fromkeys instead of set ensure the order is preserved
13
- return list(dict.fromkeys(aList))
14
-
15
-
16
- def appendUnique(aList: list, anObject: Any):
17
- """Append to list if object does not exist.
18
-
19
- :param aList: list of elements
20
- :param anObject: object you want to append
21
- """
22
- if anObject not in aList:
23
- aList.append(anObject)
24
-
25
-
26
- def fromChar(inputString: str, sepChar: str = ","):
27
- """Generates a list splitting a string by the required character(s)
28
- resulting string items are stripped and empty items are removed.
29
-
30
- :param inputString: list serialised to string
31
- :param sepChar: separator
32
- :return: list of strings or None if sepChar has a wrong type
33
- """
34
- # to prevent getting an empty String as argument
35
- if not (isinstance(inputString, str) and isinstance(sepChar, str) and sepChar):
36
- return None
37
- return [fieldString.strip() for fieldString in inputString.split(sepChar) if len(fieldString.strip()) > 0]
38
-
39
-
40
- def randomize(aList: list) -> list:
41
- """Return a randomly sorted list.
42
-
43
- :param aList: list to permute
44
- """
45
- tmpList = list(aList)
46
- random.shuffle(tmpList)
47
- return tmpList
48
-
49
-
50
- def pop(aList, popElement):
51
- """Pop the first element equal to popElement from the list.
52
-
53
- :param aList: list
54
- :type aList: python:list
55
- :param popElement: element to pop
56
- """
57
- if popElement in aList:
58
- return aList.pop(aList.index(popElement))
59
-
60
-
61
- def stringListToString(aList: list) -> str:
62
- """This function is used for making MySQL queries with a list of string elements.
63
-
64
- :param aList: list to be serialized to string for making queries
65
- """
66
- return ",".join(f"'{x}'" for x in aList)
67
-
68
-
69
- def intListToString(aList: list) -> str:
70
- """This function is used for making MySQL queries with a list of int elements.
71
-
72
- :param aList: list to be serialized to string for making queries
73
- """
74
- return ",".join(str(x) for x in aList)
75
-
76
-
77
- def getChunk(aList: list, chunkSize: int):
78
- """Generator yielding chunk from a list of a size chunkSize.
79
-
80
- :param aList: list to be splitted
81
- :param chunkSize: lenght of one chunk
82
- :raise: StopIteration
83
-
84
- Usage:
85
-
86
- >>> for chunk in getChunk( aList, chunkSize=10):
87
- process( chunk )
88
-
89
- """
90
- chunkSize = int(chunkSize)
91
- for i in range(0, len(aList), chunkSize):
92
- yield aList[i : i + chunkSize]
93
-
94
-
95
- def breakListIntoChunks(aList: list, chunkSize: int):
96
- """This function takes a list as input and breaks it into list of size 'chunkSize'.
97
- It returns a list of lists.
98
-
99
- :param aList: list of elements
100
- :param chunkSize: len of a single chunk
101
- :return: list of lists of length of chunkSize
102
- :raise: RuntimeError if numberOfFilesInChunk is less than 1
103
- """
104
- if chunkSize < 1:
105
- raise RuntimeError("chunkSize cannot be less than 1")
106
- if isinstance(aList, (set, dict, tuple, {}.keys().__class__, {}.items().__class__, {}.values().__class__)):
107
- aList = list(aList)
108
- return [chunk for chunk in getChunk(aList, chunkSize)]
109
-
110
-
111
- def getIndexInList(anItem: Any, aList: list) -> int:
112
- """Return the index of the element x in the list l
113
- or sys.maxint if it does not exist
114
-
115
- :param anItem: element to look for
116
- :param aList: list to look into
117
-
118
- :return: the index or sys.maxint
119
- """
120
- # try:
121
- if anItem in aList:
122
- return aList.index(anItem)
123
- else:
124
- return sys.maxsize
1
+ from DIRACCommon.Core.Utilities.List import * # noqa: F401,F403
@@ -1,151 +1,152 @@
1
- """ DIRAC Basic MySQL Class
2
- It provides access to the basic MySQL methods in a multithread-safe mode
3
- keeping used connections in a python Queue for further reuse.
1
+ """DIRAC Basic MySQL Class
2
+ It provides access to the basic MySQL methods in a multithread-safe mode
3
+ keeping used connections in a python Queue for further reuse.
4
4
 
5
- These are the coded methods:
5
+ These are the coded methods:
6
6
 
7
7
 
8
- __init__( host, user, passwd, name, [maxConnsInQueue=10] )
8
+ __init__( host, user, passwd, name, [maxConnsInQueue=10] )
9
9
 
10
- Initializes the Queue and tries to connect to the DB server,
11
- using the _connect method.
12
- "maxConnsInQueue" defines the size of the Queue of open connections
13
- that are kept for reuse. It also defined the maximum number of open
14
- connections available from the object.
15
- maxConnsInQueue = 0 means unlimited and it is not supported.
10
+ Initializes the Queue and tries to connect to the DB server,
11
+ using the _connect method.
12
+ "maxConnsInQueue" defines the size of the Queue of open connections
13
+ that are kept for reuse. It also defined the maximum number of open
14
+ connections available from the object.
15
+ maxConnsInQueue = 0 means unlimited and it is not supported.
16
16
 
17
17
 
18
- _except( methodName, exception, errorMessage )
18
+ _except( methodName, exception, errorMessage )
19
19
 
20
- Helper method for exceptions: the "methodName" and the "errorMessage"
21
- are printed with ERROR level, then the "exception" is printed (with
22
- full description if it is a MySQL Exception) and S_ERROR is returned
23
- with the errorMessage and the exception.
20
+ Helper method for exceptions: the "methodName" and the "errorMessage"
21
+ are printed with ERROR level, then the "exception" is printed (with
22
+ full description if it is a MySQL Exception) and S_ERROR is returned
23
+ with the errorMessage and the exception.
24
24
 
25
25
 
26
- _connect()
26
+ _connect()
27
27
 
28
- Attempts connection to DB and sets the _connected flag to True upon success.
29
- Returns S_OK or S_ERROR.
28
+ Attempts connection to DB and sets the _connected flag to True upon success.
29
+ Returns S_OK or S_ERROR.
30
30
 
31
31
 
32
- _query( cmd, [conn=conn] )
32
+ _query( cmd, [conn=conn] )
33
33
 
34
- Executes SQL command "cmd".
35
- Gets a connection from the Queue (or open a new one if none is available),
36
- the used connection is back into the Queue.
37
- If a connection to the the DB is passed as second argument this connection
38
- is used and is not in the Queue.
39
- Returns S_OK with fetchall() out in Value or S_ERROR upon failure.
34
+ Executes SQL command "cmd".
35
+ Gets a connection from the Queue (or open a new one if none is available),
36
+ the used connection is back into the Queue.
37
+ If a connection to the the DB is passed as second argument this connection
38
+ is used and is not in the Queue.
39
+ Returns S_OK with fetchall() out in Value or S_ERROR upon failure.
40
40
 
41
41
 
42
- _update( cmd, [conn=conn] )
42
+ _update( cmd, [conn=conn] )
43
43
 
44
- Executes SQL command "cmd" and issue a commit
45
- Gets a connection from the Queue (or open a new one if none is available),
46
- the used connection is back into the Queue.
47
- If a connection to the the DB is passed as second argument this connection
48
- is used and is not in the Queue
49
- Returns S_OK with number of updated registers in Value or S_ERROR upon failure.
44
+ Executes SQL command "cmd" and issue a commit
45
+ Gets a connection from the Queue (or open a new one if none is available),
46
+ the used connection is back into the Queue.
47
+ If a connection to the the DB is passed as second argument this connection
48
+ is used and is not in the Queue
49
+ Returns S_OK with number of updated registers in Value or S_ERROR upon failure.
50
50
 
51
51
 
52
- _createTables( tableDict )
52
+ _createTables( tableDict )
53
53
 
54
- Create a new Table in the DB
54
+ Create a new Table in the DB
55
55
 
56
56
 
57
- _getConnection()
57
+ _getConnection()
58
58
 
59
- Gets a connection from the Queue (or open a new one if none is available)
60
- Returns S_OK with connection in Value or S_ERROR
61
- the calling method is responsible for closing this connection once it is no
62
- longer needed.
59
+ Gets a connection from the Queue (or open a new one if none is available)
60
+ Returns S_OK with connection in Value or S_ERROR
61
+ the calling method is responsible for closing this connection once it is no
62
+ longer needed.
63
63
 
64
64
 
65
65
 
66
66
 
67
- Some high level methods have been added to avoid the need to write SQL
68
- statement in most common cases. They should be used instead of low level
69
- _insert, _update methods when ever possible.
67
+ Some high level methods have been added to avoid the need to write SQL
68
+ statement in most common cases. They should be used instead of low level
69
+ _insert, _update methods when ever possible.
70
70
 
71
- buildCondition( self, condDict = None, older = None, newer = None,
72
- timeStamp = None, orderAttribute = None, limit = False,
73
- greater = None, smaller = None ):
71
+ buildCondition( self, condDict = None, older = None, newer = None,
72
+ timeStamp = None, orderAttribute = None, limit = False,
73
+ greater = None, smaller = None ):
74
74
 
75
- Build SQL condition statement from provided condDict and other extra check on
76
- a specified time stamp.
77
- The conditions dictionary specifies for each attribute one or a List of possible
78
- values
79
- greater and smaller are dictionaries in which the keys are the names of the fields,
80
- that are requested to be >= or < than the corresponding value.
81
- For compatibility with current usage it uses Exceptions to exit in case of
82
- invalid arguments
75
+ Build SQL condition statement from provided condDict and other extra check on
76
+ a specified time stamp.
77
+ The conditions dictionary specifies for each attribute one or a List of possible
78
+ values
79
+ greater and smaller are dictionaries in which the keys are the names of the fields,
80
+ that are requested to be >= or < than the corresponding value.
81
+ For compatibility with current usage it uses Exceptions to exit in case of
82
+ invalid arguments
83
83
 
84
84
 
85
- insertFields( self, tableName, inFields = None, inValues = None, conn = None, inDict = None ):
85
+ insertFields( self, tableName, inFields = None, inValues = None, conn = None, inDict = None ):
86
86
 
87
- Insert a new row in "tableName" assigning the values "inValues" to the
88
- fields "inFields".
89
- Alternatively inDict can be used
90
- String type values will be appropriately escaped.
87
+ Insert a new row in "tableName" assigning the values "inValues" to the
88
+ fields "inFields".
89
+ Alternatively inDict can be used
90
+ String type values will be appropriately escaped.
91
91
 
92
92
 
93
- updateFields( self, tableName, updateFields = None, updateValues = None,
94
- condDict = None,
95
- limit = False, conn = None,
96
- updateDict = None,
97
- older = None, newer = None,
98
- timeStamp = None, orderAttribute = None ):
93
+ updateFields( self, tableName, updateFields = None, updateValues = None,
94
+ condDict = None,
95
+ limit = False, conn = None,
96
+ updateDict = None,
97
+ older = None, newer = None,
98
+ timeStamp = None, orderAttribute = None ):
99
99
 
100
- Update "updateFields" from "tableName" with "updateValues".
101
- updateDict alternative way to provide the updateFields and updateValues
102
- N records can match the condition
103
- return S_OK( number of updated rows )
104
- if limit is not False, the given limit is set
105
- String type values will be appropriately escaped.
100
+ Update "updateFields" from "tableName" with "updateValues".
101
+ updateDict alternative way to provide the updateFields and updateValues
102
+ N records can match the condition
103
+ return S_OK( number of updated rows )
104
+ if limit is not False, the given limit is set
105
+ String type values will be appropriately escaped.
106
106
 
107
107
 
108
- deleteEntries( self, tableName,
109
- condDict = None,
110
- limit = False, conn = None,
111
- older = None, newer = None,
112
- timeStamp = None, orderAttribute = None ):
113
-
114
- Delete rows from "tableName" with
115
- N records can match the condition
116
- if limit is not False, the given limit is set
117
- String type values will be appropriately escaped, they can be single values or lists of values.
118
-
119
-
120
- getFields( self, tableName, outFields = None,
108
+ deleteEntries( self, tableName,
121
109
  condDict = None,
122
110
  limit = False, conn = None,
123
111
  older = None, newer = None,
124
112
  timeStamp = None, orderAttribute = None ):
125
113
 
126
- Select "outFields" from "tableName" with condDict
127
- N records can match the condition
128
- return S_OK( tuple(Field,Value) )
129
- if limit is not False, the given limit is set
130
- String type values will be appropriately escaped, they can be single values or lists of values.
114
+ Delete rows from "tableName" with
115
+ N records can match the condition
116
+ if limit is not False, the given limit is set
117
+ String type values will be appropriately escaped, they can be single values or lists of values.
118
+
119
+
120
+ getFields( self, tableName, outFields = None,
121
+ condDict = None,
122
+ limit = False, conn = None,
123
+ older = None, newer = None,
124
+ timeStamp = None, orderAttribute = None ):
131
125
 
132
- for compatibility with other methods condDict keyed argument is added
126
+ Select "outFields" from "tableName" with condDict
127
+ N records can match the condition
128
+ return S_OK( tuple(Field,Value) )
129
+ if limit is not False, the given limit is set
130
+ String type values will be appropriately escaped, they can be single values or lists of values.
133
131
 
132
+ for compatibility with other methods condDict keyed argument is added
134
133
 
135
- getCounters( self, table, attrList, condDict = None, older = None,
136
- newer = None, timeStamp = None, connection = False ):
137
134
 
138
- Count the number of records on each distinct combination of AttrList, selected
139
- with condition defined by condDict and time stamps
135
+ getCounters( self, table, attrList, condDict = None, older = None,
136
+ newer = None, timeStamp = None, connection = False ):
140
137
 
138
+ Count the number of records on each distinct combination of AttrList, selected
139
+ with condition defined by condDict and time stamps
141
140
 
142
- getDistinctAttributeValues( self, table, attribute, condDict = None, older = None,
143
- newer = None, timeStamp = None, connection = False ):
144
141
 
145
- Get distinct values of a table attribute under specified conditions
142
+ getDistinctAttributeValues( self, table, attribute, condDict = None, older = None,
143
+ newer = None, timeStamp = None, connection = False ):
144
+
145
+ Get distinct values of a table attribute under specified conditions
146
146
 
147
147
 
148
148
  """
149
+
149
150
  import collections
150
151
  import functools
151
152
  import json
@@ -760,6 +761,7 @@ class MySQL:
760
761
 
761
762
  :return: S_OK with number of updated registers upon success.
762
763
  S_ERROR upon error.
764
+ lastRowId: if set, added to the returned dictionary
763
765
  """
764
766
 
765
767
  self.log.debug(f"_update: {self._safeCmd(cmd)}")
@@ -774,9 +776,11 @@ class MySQL:
774
776
  try:
775
777
  cursor = connection.cursor()
776
778
  res = cursor.execute(cmd, args=args)
779
+
777
780
  retDict = S_OK(res)
778
781
  if cursor.lastrowid:
779
782
  retDict["lastRowId"] = cursor.lastrowid
783
+
780
784
  except Exception as x:
781
785
  retDict = self._except("_update", x, "Execution failed.", cmd, debug)
782
786
 
@@ -3,10 +3,11 @@
3
3
  by default on Error they return None
4
4
  """
5
5
  import os
6
+ import threading
6
7
 
7
8
  import DIRAC
8
- from DIRAC.Core.Utilities.Subprocess import shellCall, systemCall
9
9
  from DIRAC.Core.Utilities import List
10
+ from DIRAC.Core.Utilities.Subprocess import shellCall, systemCall
10
11
 
11
12
  DEBUG = 0
12
13
 
@@ -128,3 +129,33 @@ def sourceEnv(timeout, cmdTuple, inputEnv=None):
128
129
  result["stderr"] = stderr
129
130
 
130
131
  return result
132
+
133
+
134
+ def safe_listdir(directory, timeout=60):
135
+ """This is a "safe" list directory,
136
+ for lazily-loaded File Systems like CVMFS.
137
+ There's by default a 60 seconds timeout.
138
+
139
+ .. warning::
140
+ There is no distinction between an empty directory, and a non existent one.
141
+ It will return `[]` in both cases.
142
+
143
+ :param str directory: directory to list
144
+ :param int timeout: optional timeout, in seconds. Defaults to 60.
145
+ """
146
+
147
+ def listdir(directory):
148
+ try:
149
+ return os.listdir(directory)
150
+ except FileNotFoundError:
151
+ print(f"{directory} not found")
152
+ return []
153
+
154
+ contents = []
155
+ t = threading.Thread(target=lambda: contents.extend(listdir(directory)))
156
+ t.daemon = True # don't delay program's exit
157
+ t.start()
158
+ t.join(timeout)
159
+ if t.is_alive():
160
+ return None # timeout
161
+ return contents