DIRACCommon 9.0.0a66__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 (25) hide show
  1. DIRACCommon/Core/Utilities/ClassAd/ClassAdLight.py +295 -0
  2. DIRACCommon/Core/Utilities/ClassAd/__init__.py +1 -0
  3. DIRACCommon/Core/Utilities/JDL.py +199 -0
  4. DIRACCommon/Core/Utilities/List.py +127 -0
  5. DIRACCommon/{Utils → Core/Utilities}/ReturnValues.py +1 -1
  6. DIRACCommon/Core/Utilities/StateMachine.py +185 -0
  7. DIRACCommon/Core/Utilities/TimeUtilities.py +259 -0
  8. DIRACCommon/Core/__init__.py +1 -0
  9. DIRACCommon/WorkloadManagementSystem/Client/JobState/JobManifest.py +235 -0
  10. DIRACCommon/WorkloadManagementSystem/Client/JobState/__init__.py +0 -0
  11. DIRACCommon/WorkloadManagementSystem/Client/JobStatus.py +95 -0
  12. DIRACCommon/WorkloadManagementSystem/Client/__init__.py +1 -0
  13. DIRACCommon/WorkloadManagementSystem/DB/JobDBUtils.py +170 -0
  14. DIRACCommon/WorkloadManagementSystem/DB/__init__.py +1 -0
  15. DIRACCommon/WorkloadManagementSystem/Utilities/JobModel.py +236 -0
  16. DIRACCommon/WorkloadManagementSystem/Utilities/JobStatusUtility.py +93 -0
  17. DIRACCommon/WorkloadManagementSystem/Utilities/ParametricJob.py +179 -0
  18. DIRACCommon/WorkloadManagementSystem/Utilities/__init__.py +1 -0
  19. DIRACCommon/WorkloadManagementSystem/__init__.py +1 -0
  20. {diraccommon-9.0.0a66.dist-info → diraccommon-9.0.0a67.dist-info}/METADATA +9 -4
  21. diraccommon-9.0.0a67.dist-info/RECORD +25 -0
  22. diraccommon-9.0.0a66.dist-info/RECORD +0 -7
  23. /DIRACCommon/{Utils → Core/Utilities}/DErrno.py +0 -0
  24. /DIRACCommon/{Utils → Core/Utilities}/__init__.py +0 -0
  25. {diraccommon-9.0.0a66.dist-info → diraccommon-9.0.0a67.dist-info}/WHEEL +0 -0
@@ -0,0 +1,179 @@
1
+ """ Utilities to process parametric job definitions and generate
2
+ bunches of parametric jobs. It exposes the following functions:
3
+
4
+ getParameterVectorLength() - to get the total size of the bunch of parametric jobs
5
+ generateParametricJobs() - to get a list of expanded descriptions of all the jobs
6
+ """
7
+ import re
8
+
9
+ from DIRACCommon.Core.Utilities.ClassAd.ClassAdLight import ClassAd
10
+ from DIRACCommon.Core.Utilities.ReturnValues import S_OK, S_ERROR
11
+ from DIRACCommon.Core.Utilities.DErrno import EWMSJDL
12
+
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)
@@ -0,0 +1 @@
1
+ """DIRACCommon WorkloadManagementSystem utilities"""
@@ -0,0 +1 @@
1
+ """DIRACCommon WorkloadManagementSystem utilities"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DIRACCommon
3
- Version: 9.0.0a66
3
+ Version: 9.0.0a67
4
4
  Summary: Stateless utilities extracted from DIRAC for use by DiracX and other projects
5
5
  Project-URL: Homepage, https://github.com/DIRACGrid/DIRAC
6
6
  Project-URL: Documentation, https://dirac.readthedocs.io/
@@ -14,6 +14,8 @@ Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Topic :: Scientific/Engineering
15
15
  Classifier: Topic :: System :: Distributed Computing
16
16
  Requires-Python: >=3.11
17
+ Requires-Dist: diraccfg
18
+ Requires-Dist: pydantic>=2.0.0
17
19
  Requires-Dist: typing-extensions>=4.0.0
18
20
  Provides-Extra: testing
19
21
  Requires-Dist: pytest-cov>=4.0.0; extra == 'testing'
@@ -30,8 +32,11 @@ This package solves the circular dependency issue where DiracX needs DIRAC utili
30
32
 
31
33
  ## Contents
32
34
 
33
- - `DIRACCommon.Utils.ReturnValues`: DIRAC's S_OK/S_ERROR return value system
34
- - `DIRACCommon.Utils.DErrno`: DIRAC error codes and utilities
35
+ - `DIRACCommon.Core.Utilities.ReturnValues`: DIRAC's S_OK/S_ERROR return value system
36
+ - `DIRACCommon.Core.Utilities.DErrno`: DIRAC error codes and utilities
37
+ - `DIRACCommon.Core.Utilities.ClassAd.ClassAdLight`: JDL parsing utilities
38
+ - `DIRACCommon.WorkloadManagementSystem.DB.JobDBUtils`: Job database utilities
39
+ - `DIRACCommon.WorkloadManagementSystem.Utilities.ParametricJob`: Parametric job utilities
35
40
 
36
41
  ## Installation
37
42
 
@@ -42,7 +47,7 @@ pip install DIRACCommon
42
47
  ## Usage
43
48
 
44
49
  ```python
45
- from DIRACCommon.Utils.ReturnValues import S_OK, S_ERROR
50
+ from DIRACCommon.Core.Utilities.ReturnValues import S_OK, S_ERROR
46
51
 
47
52
  def my_function():
48
53
  if success:
@@ -0,0 +1,25 @@
1
+ DIRACCommon/__init__.py,sha256=o31FFvmIiU2Wsc9nfsPZVaXYK9d3KTN0vOa8mZS6x5E,587
2
+ DIRACCommon/Core/__init__.py,sha256=Kv_Rkbm9hOPmHSnTG0_i7QR5Tck8bldITONhsoT2syg,33
3
+ DIRACCommon/Core/Utilities/DErrno.py,sha256=LUaIcKkjuioTMO3O7H9T9Pk5pHUS63Nzx3FcaP40n5c,7998
4
+ DIRACCommon/Core/Utilities/JDL.py,sha256=z4RID730tbCmbgldKfhSFc9ADfXDhUfjaBG8RpuK2Bs,6724
5
+ DIRACCommon/Core/Utilities/List.py,sha256=AahQrlQqfnh8tyA1GjGqYJfo_3v5N77IQreA8VCNXks,3758
6
+ DIRACCommon/Core/Utilities/ReturnValues.py,sha256=YDZEZrYLtI_Aa8qTnHX633F1cRupQ_UTAnI7aSlf0sI,8733
7
+ DIRACCommon/Core/Utilities/StateMachine.py,sha256=5Pwpc2wmCgb6PwyUH2qe9HZwBMyzkhFTBA7cixso1Sg,6767
8
+ DIRACCommon/Core/Utilities/TimeUtilities.py,sha256=wXuYIwECbLSFdVoNM0iSYoCrz6_iL-JrMV1yVv3FloA,9026
9
+ DIRACCommon/Core/Utilities/__init__.py,sha256=hwOqqYwQDINF-D3eKKBC1r-B_jEnQ5ZSdJvc7rIv_fY,56
10
+ DIRACCommon/Core/Utilities/ClassAd/ClassAdLight.py,sha256=7450ECzxnJQpIjzbaE-uFp3ISE55iL6YM-TRqyebZTY,9597
11
+ DIRACCommon/Core/Utilities/ClassAd/__init__.py,sha256=z0yRe-wRxIHE-Sp3tnyC37S6z38dZHCxuqf3ZV1OyzQ,40
12
+ DIRACCommon/WorkloadManagementSystem/__init__.py,sha256=XMOUD0OcPVo-mjuA0vU-mbtf9K0kBMy5I5sELrX3HEs,53
13
+ DIRACCommon/WorkloadManagementSystem/Client/JobStatus.py,sha256=lBfPYa_RRjJlWEU5eqrbWFaSl1081CqSDjhI6B7-qeA,2813
14
+ DIRACCommon/WorkloadManagementSystem/Client/__init__.py,sha256=ssMppR0P3iXlUaqWPjl1Y5AlQ6LgUAsRa9-5lVkBsL0,60
15
+ DIRACCommon/WorkloadManagementSystem/Client/JobState/JobManifest.py,sha256=E3DVRzAHUFAFa9baqEbAMr-4cu6tTXuVRVdl7XgUX7I,7380
16
+ DIRACCommon/WorkloadManagementSystem/Client/JobState/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ DIRACCommon/WorkloadManagementSystem/DB/JobDBUtils.py,sha256=YU97uk0fjwYN6O8nkD6XjnZ7k9ovhSLYjytqI3oLRfU,5777
18
+ DIRACCommon/WorkloadManagementSystem/DB/__init__.py,sha256=CXWy4bdKeG6ml9T5r8-E7EyfDBNE79I_bs13qYI7yY8,56
19
+ DIRACCommon/WorkloadManagementSystem/Utilities/JobModel.py,sha256=kpvsxQnR-j9Y9I38qUWLD7coFRssLwtJCtSNAbjFh1Y,8973
20
+ DIRACCommon/WorkloadManagementSystem/Utilities/JobStatusUtility.py,sha256=Kf4o1bp25JLsRb-Vsc4NuM6w1Io2hg_ALtIyqBk-Qhw,3628
21
+ DIRACCommon/WorkloadManagementSystem/Utilities/ParametricJob.py,sha256=iYd29TgGXZk31pQLPw_frIhcmZB9X-RmuDmIRxzgiww,7405
22
+ DIRACCommon/WorkloadManagementSystem/Utilities/__init__.py,sha256=XMOUD0OcPVo-mjuA0vU-mbtf9K0kBMy5I5sELrX3HEs,53
23
+ diraccommon-9.0.0a67.dist-info/METADATA,sha256=NA1PLIfXlFQ4tWmuf1m_7mSvSlHBuHVudhsOIC_VRDs,2575
24
+ diraccommon-9.0.0a67.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
+ diraccommon-9.0.0a67.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- DIRACCommon/__init__.py,sha256=o31FFvmIiU2Wsc9nfsPZVaXYK9d3KTN0vOa8mZS6x5E,587
2
- DIRACCommon/Utils/DErrno.py,sha256=LUaIcKkjuioTMO3O7H9T9Pk5pHUS63Nzx3FcaP40n5c,7998
3
- DIRACCommon/Utils/ReturnValues.py,sha256=9lEFPeu5MV1zCWTOgvd2779QMZeCKSnTW0LWa873eBE,8724
4
- DIRACCommon/Utils/__init__.py,sha256=hwOqqYwQDINF-D3eKKBC1r-B_jEnQ5ZSdJvc7rIv_fY,56
5
- diraccommon-9.0.0a66.dist-info/METADATA,sha256=0ci1O9p3PmrdZAmamil4OG-rXoZLygLuLXJuqsd3JJU,2248
6
- diraccommon-9.0.0a66.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- diraccommon-9.0.0a66.dist-info/RECORD,,
File without changes
File without changes