DIRAC 9.0.0a64__py3-none-any.whl → 9.0.0a67__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 (47) hide show
  1. DIRAC/ConfigurationSystem/Client/LocalConfiguration.py +11 -8
  2. DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +1 -1
  3. DIRAC/Core/Security/IAMService.py +4 -3
  4. DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
  5. DIRAC/Core/Utilities/DErrno.py +5 -309
  6. DIRAC/Core/Utilities/JDL.py +1 -195
  7. DIRAC/Core/Utilities/List.py +1 -127
  8. DIRAC/Core/Utilities/ReturnValues.py +7 -252
  9. DIRAC/Core/Utilities/StateMachine.py +12 -178
  10. DIRAC/Core/Utilities/TimeUtilities.py +10 -253
  11. DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
  12. DIRAC/Core/scripts/dirac_agent.py +1 -1
  13. DIRAC/DataManagementSystem/DB/FTS3DB.py +3 -0
  14. DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
  15. DIRAC/Resources/Catalog/RucioFileCatalogClient.py +1 -1
  16. DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
  17. DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +1 -1
  18. DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
  19. DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +1 -1
  20. DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +1 -1
  21. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +2 -0
  22. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
  23. DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
  24. DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -93
  25. DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
  26. DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
  27. DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
  28. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +4 -2
  29. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +21 -5
  30. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
  31. DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +1 -1
  32. DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -199
  33. DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +1 -63
  34. DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
  35. DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +0 -123
  36. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -5
  37. DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
  38. DIRAC/__init__.py +55 -54
  39. {dirac-9.0.0a64.dist-info → dirac-9.0.0a67.dist-info}/METADATA +2 -1
  40. {dirac-9.0.0a64.dist-info → dirac-9.0.0a67.dist-info}/RECORD +44 -45
  41. DIRAC/Core/Utilities/test/Test_List.py +0 -150
  42. DIRAC/Core/Utilities/test/Test_Time.py +0 -88
  43. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobAdministration.py +0 -28
  44. {dirac-9.0.0a64.dist-info → dirac-9.0.0a67.dist-info}/WHEEL +0 -0
  45. {dirac-9.0.0a64.dist-info → dirac-9.0.0a67.dist-info}/entry_points.txt +0 -0
  46. {dirac-9.0.0a64.dist-info → dirac-9.0.0a67.dist-info}/licenses/LICENSE +0 -0
  47. {dirac-9.0.0a64.dist-info → dirac-9.0.0a67.dist-info}/top_level.txt +0 -0
@@ -4,176 +4,12 @@
4
4
  getParameterVectorLength() - to get the total size of the bunch of parametric jobs
5
5
  generateParametricJobs() - to get a list of expanded descriptions of all the jobs
6
6
  """
7
- import re
8
7
 
9
- from DIRAC.Core.Utilities.ClassAd.ClassAdLight import ClassAd
10
- from DIRAC.Core.Utilities.ReturnValues import S_OK, S_ERROR
11
- from DIRAC.Core.Utilities.DErrno import EWMSJDL
8
+ # Import from DIRACCommon for backward compatibility
9
+ from DIRACCommon.WorkloadManagementSystem.Utilities.ParametricJob import (
10
+ getParameterVectorLength,
11
+ generateParametricJobs,
12
+ )
12
13
 
13
-
14
- def __getParameterSequence(nPar, parList=[], parStart=1, parStep=0, parFactor=1):
15
- if parList:
16
- if nPar != len(parList):
17
- return []
18
- else:
19
- parameterList = list(parList)
20
- else:
21
- # The first parameter must have the same type as the other ones even if not defined explicitly
22
- parameterList = [parStart * type(parFactor)(1) + type(parStep)(0)]
23
- for np in range(1, nPar):
24
- parameterList.append(parameterList[np - 1] * parFactor + parStep)
25
-
26
- return parameterList
27
-
28
-
29
- def getParameterVectorLength(jobClassAd):
30
- """Get the length of parameter vector in the parametric job description
31
-
32
- :param jobClassAd: ClassAd job description object
33
- :return: result structure with the Value: int number of parameter values, None if not a parametric job
34
- """
35
-
36
- nParValues = None
37
- attributes = jobClassAd.getAttributes()
38
- for attribute in attributes:
39
- if attribute.startswith("Parameters"):
40
- if jobClassAd.isAttributeList(attribute):
41
- parameterList = jobClassAd.getListFromExpression(attribute)
42
- nThisParValues = len(parameterList)
43
- else:
44
- nThisParValues = jobClassAd.getAttributeInt(attribute)
45
- if nParValues is not None and nParValues != nThisParValues:
46
- return S_ERROR(
47
- EWMSJDL,
48
- "Different length of parameter vectors: for %s, %s != %d" % (attribute, nParValues, nThisParValues),
49
- )
50
- nParValues = nThisParValues
51
- if nParValues is not None and nParValues <= 0:
52
- return S_ERROR(EWMSJDL, "Illegal number of job parameters %d" % (nParValues))
53
- return S_OK(nParValues)
54
-
55
-
56
- def __updateAttribute(classAd, attribute, parName, parValue):
57
- # If there is something to do:
58
- pattern = r"%%\(%s\)s" % parName
59
- if parName == "0":
60
- pattern = "%s"
61
- expr = classAd.get_expression(attribute)
62
- if not re.search(pattern, expr):
63
- return False
64
-
65
- pattern = "%%(%s)s" % parName
66
- if parName == "0":
67
- pattern = "%s"
68
-
69
- parValue = parValue.strip()
70
- if classAd.isAttributeList(attribute):
71
- parValue = parValue.strip()
72
- if parValue.startswith("{"):
73
- parValue = parValue.lstrip("{").rstrip("}").strip()
74
-
75
- expr = classAd.get_expression(attribute)
76
- newexpr = expr.replace(pattern, str(parValue))
77
- classAd.set_expression(attribute, newexpr)
78
- return True
79
-
80
-
81
- def generateParametricJobs(jobClassAd):
82
- """Generate a series of ClassAd job descriptions expanding
83
- job parameters
84
-
85
- :param jobClassAd: ClassAd job description object
86
- :return: list of ClassAd job description objects
87
- """
88
- if not jobClassAd.lookupAttribute("Parameters"):
89
- return S_OK([jobClassAd.asJDL()])
90
-
91
- result = getParameterVectorLength(jobClassAd)
92
- if not result["OK"]:
93
- return result
94
- nParValues = result["Value"]
95
- if nParValues is None:
96
- return S_ERROR(EWMSJDL, "Can not determine the number of job parameters")
97
-
98
- parameterDict = {}
99
- attributes = jobClassAd.getAttributes()
100
- for attribute in attributes:
101
- for key in ["Parameters", "ParameterStart", "ParameterStep", "ParameterFactor"]:
102
- if attribute.startswith(key):
103
- seqID = "0" if "." not in attribute else attribute.split(".")[1]
104
- parameterDict.setdefault(seqID, {})
105
- if key == "Parameters":
106
- if jobClassAd.isAttributeList(attribute):
107
- parList = jobClassAd.getListFromExpression(attribute)
108
- if len(parList) != nParValues:
109
- return S_ERROR(EWMSJDL, "Inconsistent parametric job description")
110
- parameterDict[seqID]["ParameterList"] = parList
111
- else:
112
- if attribute != "Parameters":
113
- return S_ERROR(EWMSJDL, "Inconsistent parametric job description")
114
- nPar = jobClassAd.getAttributeInt(attribute)
115
- if nPar is None:
116
- value = jobClassAd.get_expression(attribute)
117
- return S_ERROR(EWMSJDL, f"Inconsistent parametric job description: {attribute}={value}")
118
- parameterDict[seqID]["Parameters"] = nPar
119
- else:
120
- value = jobClassAd.getAttributeInt(attribute)
121
- if value is None:
122
- value = jobClassAd.getAttributeFloat(attribute)
123
- if value is None:
124
- value = jobClassAd.get_expression(attribute)
125
- return S_ERROR(f"Illegal value for {attribute} JDL field: {value}")
126
- parameterDict[seqID][key] = value
127
-
128
- if "0" in parameterDict and not parameterDict.get("0"):
129
- parameterDict.pop("0")
130
-
131
- parameterLists = {}
132
- for seqID in parameterDict:
133
- parList = __getParameterSequence(
134
- nParValues,
135
- parList=parameterDict[seqID].get("ParameterList", []),
136
- parStart=parameterDict[seqID].get("ParameterStart", 1),
137
- parStep=parameterDict[seqID].get("ParameterStep", 0),
138
- parFactor=parameterDict[seqID].get("ParameterFactor", 1),
139
- )
140
- if not parList:
141
- return S_ERROR(EWMSJDL, "Inconsistent parametric job description")
142
-
143
- parameterLists[seqID] = parList
144
-
145
- jobDescList = []
146
- jobDesc = jobClassAd.asJDL()
147
- # Width of the sequential parameter number
148
- zLength = len(str(nParValues - 1))
149
- for n in range(nParValues):
150
- newJobDesc = jobDesc
151
- newJobDesc = newJobDesc.replace("%n", str(n).zfill(zLength))
152
- newClassAd = ClassAd(newJobDesc)
153
- for seqID in parameterLists:
154
- parameter = parameterLists[seqID][n]
155
- for attribute in newClassAd.getAttributes():
156
- __updateAttribute(newClassAd, attribute, seqID, str(parameter))
157
-
158
- for seqID in parameterLists:
159
- for attribute in ["Parameters", "ParameterStart", "ParameterStep", "ParameterFactor"]:
160
- if seqID == "0":
161
- newClassAd.deleteAttribute(attribute)
162
- else:
163
- newClassAd.deleteAttribute(f"{attribute}.{seqID}")
164
-
165
- parameter = parameterLists[seqID][n]
166
- if seqID == "0":
167
- attribute = "Parameter"
168
- else:
169
- attribute = f"Parameter.{seqID}"
170
- if isinstance(parameter, str) and parameter.startswith("{"):
171
- newClassAd.insertAttributeInt(attribute, str(parameter))
172
- else:
173
- newClassAd.insertAttributeString(attribute, str(parameter))
174
-
175
- newClassAd.insertAttributeInt("ParameterNumber", n)
176
- newJDL = newClassAd.asJDL()
177
- jobDescList.append(newJDL)
178
-
179
- return S_OK(jobDescList)
14
+ # Re-export for backward compatibility
15
+ __all__ = ["getParameterVectorLength", "generateParametricJobs"]
@@ -1,127 +1,4 @@
1
- from DIRAC import S_ERROR, S_OK, gLogger
2
- from DIRAC.StorageManagementSystem.DB.StorageManagementDB import StorageManagementDB
3
1
  from DIRAC.WorkloadManagementSystem.Client import JobStatus
4
- from DIRAC.WorkloadManagementSystem.DB.JobDB import JobDB
5
- from DIRAC.WorkloadManagementSystem.DB.PilotAgentsDB import PilotAgentsDB
6
- from DIRAC.WorkloadManagementSystem.DB.TaskQueueDB import TaskQueueDB
7
- from DIRAC.WorkloadManagementSystem.Service.JobPolicy import RIGHT_DELETE, RIGHT_KILL
8
-
9
-
10
- def _deleteJob(jobID, force=False):
11
- """Set the job status to "Deleted"
12
- and remove the pilot that ran and its logging info if the pilot is finished.
13
-
14
- :param int jobID: job ID
15
- :return: S_OK()/S_ERROR()
16
- """
17
- if not (result := JobDB().setJobStatus(jobID, JobStatus.DELETED, "Checking accounting", force=force))["OK"]:
18
- gLogger.warn("Failed to set job Deleted status", result["Message"])
19
- return result
20
-
21
- if not (result := TaskQueueDB().deleteJob(jobID))["OK"]:
22
- gLogger.warn("Failed to delete job from the TaskQueue")
23
-
24
- # if it was the last job for the pilot
25
- result = PilotAgentsDB().getPilotsForJobID(jobID)
26
- if not result["OK"]:
27
- gLogger.error("Failed to get Pilots for JobID", result["Message"])
28
- return result
29
- for pilot in result["Value"]:
30
- res = PilotAgentsDB().getJobsForPilot(pilot)
31
- if not res["OK"]:
32
- gLogger.error("Failed to get jobs for pilot", res["Message"])
33
- return res
34
- if not res["Value"]: # if list of jobs for pilot is empty, delete pilot
35
- result = PilotAgentsDB().getPilotInfo(pilotID=pilot)
36
- if not result["OK"]:
37
- gLogger.error("Failed to get pilot info", result["Message"])
38
- return result
39
- ret = PilotAgentsDB().deletePilot(result["Value"]["PilotJobReference"])
40
- if not ret["OK"]:
41
- gLogger.error("Failed to delete pilot from PilotAgentsDB", ret["Message"])
42
- return ret
43
-
44
- return S_OK()
45
-
46
-
47
- def _killJob(jobID, sendKillCommand=True, force=False):
48
- """Kill one job
49
-
50
- :param int jobID: job ID
51
- :param bool sendKillCommand: send kill command
52
-
53
- :return: S_OK()/S_ERROR()
54
- """
55
- if sendKillCommand:
56
- if not (result := JobDB().setJobCommand(jobID, "Kill"))["OK"]:
57
- gLogger.warn("Failed to set job Kill command", result["Message"])
58
- return result
59
-
60
- gLogger.info("Job marked for termination", jobID)
61
- if not (result := JobDB().setJobStatus(jobID, JobStatus.KILLED, "Marked for termination", force=force))["OK"]:
62
- gLogger.warn("Failed to set job Killed status", result["Message"])
63
- if not (result := TaskQueueDB().deleteJob(jobID))["OK"]:
64
- gLogger.warn("Failed to delete job from the TaskQueue", result["Message"])
65
-
66
- return S_OK()
67
-
68
-
69
- def kill_delete_jobs(right, validJobList, nonauthJobList=[], force=False):
70
- """Kill (== set the status to "KILLED") or delete (== set the status to "DELETED") jobs as necessary
71
-
72
- :param str right: RIGHT_KILL or RIGHT_DELETE
73
-
74
- :return: S_OK()/S_ERROR()
75
- """
76
- badIDs = []
77
-
78
- killJobList = []
79
- deleteJobList = []
80
- if validJobList:
81
- result = JobDB().getJobsAttributes(killJobList, ["Status"])
82
- if not result["OK"]:
83
- return result
84
- jobStates = result["Value"]
85
-
86
- # Get the jobs allowed to transition to the Killed state
87
- killJobList.extend(_filterJobStateTransition(jobStates, JobStatus.KILLED))
88
-
89
- if right == RIGHT_DELETE:
90
- # Get the jobs allowed to transition to the Deleted state
91
- deleteJobList.extend(_filterJobStateTransition(jobStates, JobStatus.DELETED))
92
-
93
- for jobID in killJobList:
94
- result = _killJob(jobID, force=force)
95
- if not result["OK"]:
96
- badIDs.append(jobID)
97
-
98
- for jobID in deleteJobList:
99
- result = _deleteJob(jobID, force=force)
100
- if not result["OK"]:
101
- badIDs.append(jobID)
102
-
103
- # Look for jobs that are in the Staging state to send kill signal to the stager
104
- stagingJobList = [jobID for jobID, sDict in jobStates.items() if sDict["Status"] == JobStatus.STAGING]
105
-
106
- if stagingJobList:
107
- stagerDB = StorageManagementDB()
108
- gLogger.info("Going to send killing signal to stager as well!")
109
- result = stagerDB.killTasksBySourceTaskID(stagingJobList)
110
- if not result["OK"]:
111
- gLogger.warn("Failed to kill some Stager tasks", result["Message"])
112
-
113
- if nonauthJobList or badIDs:
114
- result = S_ERROR("Some jobs failed deletion")
115
- if nonauthJobList:
116
- gLogger.warn("Non-authorized JobIDs won't be deleted", str(nonauthJobList))
117
- result["NonauthorizedJobIDs"] = nonauthJobList
118
- if badIDs:
119
- gLogger.warn("JobIDs failed to be deleted", str(badIDs))
120
- result["FailedJobIDs"] = badIDs
121
- return result
122
-
123
- jobsList = killJobList if right == RIGHT_KILL else deleteJobList
124
- return S_OK(jobsList)
125
2
 
126
3
 
127
4
  def _filterJobStateTransition(jobStates, candidateState):
@@ -175,11 +175,7 @@ def test_logLevelValidator_invalid():
175
175
 
176
176
  def test_platformValidator_valid():
177
177
  """Test the platform validator with valid input."""
178
- with patch(
179
- "DIRAC.WorkloadManagementSystem.Utilities.JobModel.getDIRACPlatforms",
180
- return_value=S_OK(["x86_64-slc6-gcc62-opt"]),
181
- ):
182
- job = BaseJobDescriptionModel(executable=EXECUTABLE, platform="x86_64-slc6-gcc62-opt")
178
+ job = BaseJobDescriptionModel(executable=EXECUTABLE, platform="x86_64-slc6-gcc62-opt")
183
179
  assert job.platform == "x86_64-slc6-gcc62-opt"
184
180
 
185
181
 
@@ -1,138 +1,55 @@
1
- """ This is a test of the parametric job generation tools
2
- """
1
+ """ This is a test of the parametric job generation tools"""
3
2
  # pylint: disable= missing-docstring
4
3
 
5
4
  import pytest
6
5
 
6
+ # Test imports from DIRAC to verify backward compatibility
7
7
  from DIRAC.WorkloadManagementSystem.Utilities.ParametricJob import generateParametricJobs, getParameterVectorLength
8
8
  from DIRAC.Core.Utilities.ClassAd.ClassAdLight import ClassAd
9
9
 
10
- TEST_JDL_NO_PARAMETERS = """
11
- [
12
- Executable = "my_executable";
13
- Arguments = "%s";
14
- JobName = "Test_%n";
15
- ]
16
- """
17
10
 
18
- TEST_JDL_SIMPLE = """
19
- [
20
- Executable = "my_executable";
21
- Arguments = "%s";
22
- JobName = "Test_%n";
23
- Parameters = { "a", "b", "c" }
24
- ]
25
- """
26
-
27
- TEST_JDL_SIMPLE_BUNCH = """
28
- [
29
- Executable = "my_executable";
30
- Arguments = "%s";
31
- JobName = "Test_%n";
32
- Parameters = 3;
33
- ParameterStart = 5;
34
- ]
35
- """
36
-
37
- TEST_JDL_SIMPLE_PROGRESSION = """
38
- [
39
- Executable = "my_executable";
40
- Arguments = "%s";
41
- JobName = "Test_%n";
42
- Parameters = 3;
43
- ParameterStart = 1;
44
- ParameterStep = 1;
45
- ParameterFactor = 2;
46
- ]
47
- """
48
-
49
- TEST_JDL_MULTI = """
50
- [
51
- Executable = "my_executable";
52
- Arguments = "%(A)s %(B)s";
53
- JobName = "Test_%n";
54
- Parameters = 3;
55
- ParameterStart.A = 1;
56
- ParameterStep.A = 1;
57
- ParameterFactor.A = 2;
58
- Parameters.B = { "a","b","c" };
59
- ]
60
- """
61
-
62
- TEST_JDL_MULTI_BAD = """
63
- [
64
- Executable = "my_executable";
65
- Arguments = "%(A)s %(B)s";
66
- JobName = "Test_%n";
67
- Parameters = 3;
68
- ParameterStart.A = 1;
69
- ParameterStep.A = 1;
70
- ParameterFactor.A = 2;
71
- Parameters.B = { "a","b","c","d" };
72
- ]
73
- """
74
-
75
-
76
- @pytest.mark.parametrize(
77
- "jdl, expectedArguments",
78
- [
79
- (TEST_JDL_SIMPLE, ["a", "b", "c"]),
80
- (TEST_JDL_SIMPLE_BUNCH, ["5", "5", "5"]),
81
- (TEST_JDL_SIMPLE_PROGRESSION, ["1", "3", "7"]),
82
- (TEST_JDL_MULTI, ["1 a", "3 b", "7 c"]),
83
- (TEST_JDL_NO_PARAMETERS, []),
84
- ],
85
- )
86
- def test_getParameterVectorLength_successful(jdl: str, expectedArguments: list[str]):
11
+ def test_backward_compatibility_import():
12
+ """Test that imports from DIRAC still work (backward compatibility)"""
87
13
  # Arrange
88
- jobDescription = ClassAd(jdl)
89
-
90
- # Act
91
- result = getParameterVectorLength(jobDescription)
92
-
93
- # Assert
94
- assert result["OK"], result["Message"]
95
- if expectedArguments:
96
- assert result["Value"] == len(expectedArguments)
97
- else:
98
- assert result["Value"] == None
99
-
100
-
101
- @pytest.mark.parametrize("jdl", [TEST_JDL_MULTI_BAD])
102
- def test_getParameterVectorLength_unsuccessful(jdl: str):
103
- # Arrange
104
- jobDescription = ClassAd(jdl)
105
-
106
- # Act
107
- result = getParameterVectorLength(jobDescription)
108
-
109
- # Assert
110
- assert not result["OK"], result["Value"]
111
-
112
-
113
- @pytest.mark.parametrize(
114
- "jdl, expectedArguments",
14
+ jdl = """
115
15
  [
116
- (TEST_JDL_SIMPLE, ["a", "b", "c"]),
117
- (TEST_JDL_SIMPLE_BUNCH, ["5", "5", "5"]),
118
- (TEST_JDL_SIMPLE_PROGRESSION, ["1", "3", "7"]),
119
- (TEST_JDL_MULTI, ["1 a", "3 b", "7 c"]),
120
- ],
121
- )
122
- def test_generateParametricJobs(jdl: str, expectedArguments: list[str]):
123
- # Arrange
124
- parametricJobDescription = ClassAd(jdl)
125
-
126
- # Act
127
- result = generateParametricJobs(parametricJobDescription)
128
-
129
- # Assert
130
- assert result["OK"], result["Message"]
131
- assert result["Value"]
132
- jobDescList = result["Value"]
133
- assert len(jobDescList) == len(expectedArguments)
134
-
135
- for i in range(len(jobDescList)):
136
- jobDescription = ClassAd(jobDescList[i])
137
- assert jobDescription.getAttributeString("JobName") == f"Test_{i}"
138
- assert jobDescription.getAttributeString("Arguments") == expectedArguments[i]
16
+ Executable = "my_executable";
17
+ Arguments = "%s";
18
+ JobName = "Test_%n";
19
+ Parameters = { "a", "b", "c" }
20
+ ]
21
+ """
22
+
23
+ # Act - Test that we can import and use the functions from DIRAC
24
+ jobDescription = ClassAd(jdl)
25
+ vector_result = getParameterVectorLength(jobDescription)
26
+ generate_result = generateParametricJobs(jobDescription)
27
+
28
+ # Assert - Verify functions work correctly
29
+ assert vector_result["OK"]
30
+ assert vector_result["Value"] == 3
31
+ assert generate_result["OK"]
32
+ assert len(generate_result["Value"]) == 3
33
+
34
+
35
+ # Import and run the comprehensive tests from DIRACCommon to avoid duplication
36
+ # This ensures the DIRAC re-exports work with the full test suite
37
+ try:
38
+ from DIRACCommon.tests.WorkloadManagementSystem.Utilities.test_ParametricJob import (
39
+ test_getParameterVectorLength_successful,
40
+ test_getParameterVectorLength_unsuccessful,
41
+ test_generateParametricJobs,
42
+ )
43
+
44
+ # Re-export the DIRACCommon tests so they run as part of DIRAC test suite
45
+ # This validates that the backward compatibility imports work correctly
46
+ __all__ = [
47
+ "test_backward_compatibility_import",
48
+ "test_getParameterVectorLength_successful",
49
+ "test_getParameterVectorLength_unsuccessful",
50
+ "test_generateParametricJobs",
51
+ ]
52
+
53
+ except ImportError:
54
+ # If DIRACCommon tests can't be imported, just run the backward compatibility test
55
+ __all__ = ["test_backward_compatibility_import"]
DIRAC/__init__.py CHANGED
@@ -1,59 +1,60 @@
1
1
  """
2
- DIRAC - Distributed Infrastructure with Remote Agent Control
3
-
4
- The distributed data production and analysis system of LHCb and other VOs.
5
-
6
- DIRAC is a software framework for distributed computing which
7
- allows to integrate various computing resources in a single
8
- system. At the same time it integrates all kinds of computing
9
- activities like Monte Carlo simulations, data processing, or
10
- final user analysis.
11
-
12
- It is build as number of cooperating systems:
13
- - Accounting
14
- - Configuration
15
- - Core
16
- - Base
17
- - Security
18
- - Utilities
19
- - Workflow
20
- - Framework
21
- - RequestManagement
22
- - Resources
23
- - Transformation
24
-
25
- Which are used by other system providing functionality to
26
- the end user:
27
- - DataManagement
28
- - Interfaces
29
- - ResourceStatus
30
- - StorageManagement
31
- - WorkloadManagement
32
-
33
- It defines the following data members:
34
- - version: DIRAC version string
35
-
36
- - errorMail: mail address for important errors
37
- - alarmMail: mail address for important alarms
38
-
39
- It loads Modules from :
40
- - DIRAC.Core.Utililies
41
-
42
- It loads:
43
- - S_OK: OK return structure
44
- - S_ERROR: ERROR return structure
45
- - gLogger: global Logger object
46
- - gConfig: global Config object
47
-
48
- It defines the following functions:
49
- - abort: aborts execution
50
- - exit: finish execution using callbacks
51
- - siteName: returns DIRAC name for current site
52
-
53
- - getPlatform(): DIRAC platform string for current host
54
- - getPlatformTuple(): DIRAC platform tuple for current host
2
+ DIRAC - Distributed Infrastructure with Remote Agent Control
3
+
4
+ The distributed data production and analysis system of LHCb and other VOs.
5
+
6
+ DIRAC is a software framework for distributed computing which
7
+ allows to integrate various computing resources in a single
8
+ system. At the same time it integrates all kinds of computing
9
+ activities like Monte Carlo simulations, data processing, or
10
+ final user analysis.
11
+
12
+ It is build as number of cooperating systems:
13
+ - Accounting
14
+ - Configuration
15
+ - Core
16
+ - Base
17
+ - Security
18
+ - Utilities
19
+ - Workflow
20
+ - Framework
21
+ - RequestManagement
22
+ - Resources
23
+ - Transformation
24
+
25
+ Which are used by other system providing functionality to
26
+ the end user:
27
+ - DataManagement
28
+ - Interfaces
29
+ - ResourceStatus
30
+ - StorageManagement
31
+ - WorkloadManagement
32
+
33
+ It defines the following data members:
34
+ - version: DIRAC version string
35
+
36
+ - errorMail: mail address for important errors
37
+ - alarmMail: mail address for important alarms
38
+
39
+ It loads Modules from :
40
+ - DIRAC.Core.Utililies
41
+
42
+ It loads:
43
+ - S_OK: OK return structure
44
+ - S_ERROR: ERROR return structure
45
+ - gLogger: global Logger object
46
+ - gConfig: global Config object
47
+
48
+ It defines the following functions:
49
+ - abort: aborts execution
50
+ - exit: finish execution using callbacks
51
+ - siteName: returns DIRAC name for current site
52
+
53
+ - getPlatform(): DIRAC platform string for current host
54
+ - getPlatformTuple(): DIRAC platform tuple for current host
55
55
 
56
56
  """
57
+
57
58
  import importlib.metadata
58
59
  import os
59
60
  import re
@@ -237,7 +238,7 @@ def initialize(
237
238
  log_level = getattr(LogLevel, gLogger.getLevel())
238
239
  gLogger.setLevel(LogLevel.ALWAYS)
239
240
  try:
240
- returnValueOrRaise(localCfg.initialize())
241
+ returnValueOrRaise(localCfg.initialize(requireSuccessfulSync=require_auth))
241
242
  finally:
242
243
  # Restore the pre-existing log level
243
244
  gLogger.setLevel(log_level)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DIRAC
3
- Version: 9.0.0a64
3
+ Version: 9.0.0a67
4
4
  Summary: DIRAC is an interware, meaning a software framework for distributed computing.
5
5
  Home-page: https://github.com/DIRACGrid/DIRAC/
6
6
  License: GPL-3.0-only
@@ -19,6 +19,7 @@ Requires-Dist: cachetools
19
19
  Requires-Dist: certifi
20
20
  Requires-Dist: cwltool
21
21
  Requires-Dist: diraccfg
22
+ Requires-Dist: DIRACCommon==v9.0.0a67
22
23
  Requires-Dist: diracx-client>=v0.0.1a18
23
24
  Requires-Dist: diracx-core>=v0.0.1a18
24
25
  Requires-Dist: db12