1+ """ ClassAd Class - a light purely Python representation of the
2+ Condor ClassAd library.
3+ """
4+
5+
6+ class ClassAd :
7+ def __init__ (self , jdl ):
8+ """ClassAd constructor from a JDL string"""
9+ self .contents = {}
10+ result = self .__analyse_jdl (jdl )
11+ if result :
12+ self .contents = result
13+
14+ def __analyse_jdl (self , jdl , index = 0 ):
15+ """Analyse one [] jdl enclosure"""
16+
17+ jdl = jdl .strip ()
18+
19+ # Strip all the blanks first
20+ # temp = jdl.replace(' ','').replace('\n','')
21+ temp = jdl
22+
23+ result = {}
24+
25+ if temp [0 ] != "[" or temp [- 1 ] != "]" :
26+ print ("Invalid JDL: it should start with [ and end with ]" )
27+ return result
28+
29+ # Parse the jdl string now
30+ body = temp [1 :- 1 ]
31+ index = 0
32+ namemode = 1
33+ valuemode = 0
34+ while index < len (body ):
35+ if namemode :
36+ ind = body .find ("=" , index )
37+ if ind != - 1 :
38+ name = body [index :ind ]
39+ index = ind + 1
40+ valuemode = 1
41+ namemode = 0
42+ else :
43+ break
44+ elif valuemode :
45+ ind1 = body .find ("[" , index )
46+ ind2 = body .find (";" , index )
47+ if ind1 != - 1 and ind1 < ind2 :
48+ value , newind = self .__find_subjdl (body , ind1 )
49+ elif ind1 == - 1 and ind2 == - 1 :
50+ value = body [index :]
51+ newind = len (body )
52+ else :
53+ if index == ind2 :
54+ return {}
55+ else :
56+ value = body [index :ind2 ]
57+ newind = ind2 + 1
58+
59+ result [name .strip ()] = value .strip ().replace ("\n " , "" )
60+ index = newind
61+ valuemode = 0
62+ namemode = 1
63+
64+ return result
65+
66+ def __find_subjdl (self , body , index ):
67+ """Find a full [] enclosure starting from index"""
68+ result = ""
69+ if body [index ] != "[" :
70+ return (result , 0 )
71+
72+ depth = 0
73+ ind = index
74+ while depth < 10 :
75+ ind1 = body .find ("]" , ind + 1 )
76+ ind2 = body .find ("[" , ind + 1 )
77+ if ind2 != - 1 and ind2 < ind1 :
78+ depth += 1
79+ ind = ind2
80+ else :
81+ if depth > 0 :
82+ depth -= 1
83+ ind = ind1
84+ else :
85+ result = body [index : ind1 + 1 ]
86+ if body [ind1 + 1 ] == ";" :
87+ return (result , ind1 + 2 )
88+ return result , 0
89+
90+ return result , 0
91+
92+ def insertAttributeInt (self , name , attribute ):
93+ """Insert a named integer attribute"""
94+
95+ self .contents [name ] = str (attribute )
96+
97+ def insertAttributeBool (self , name , attribute ):
98+ """Insert a named boolean attribute"""
99+
100+ if attribute :
101+ self .contents [name ] = "true"
102+ else :
103+ self .contents [name ] = "false"
104+
105+ def insertAttributeString (self , name , attribute ):
106+ """Insert a named string attribute"""
107+
108+ self .contents [name ] = '"' + str (attribute ) + '"'
109+
110+ def insertAttributeVectorString (self , name , attributelist ):
111+ """Insert a named string list attribute"""
112+
113+ tmp = ['"' + x + '"' for x in attributelist ]
114+ tmpstr = "," .join (tmp )
115+ self .contents [name ] = "{" + tmpstr + "}"
116+
117+ def insertAttributeVectorInt (self , name , attributelist ):
118+ """Insert a named string list attribute"""
119+
120+ tmp = [str (x ) for x in attributelist ]
121+ tmpstr = "," .join (tmp )
122+ self .contents [name ] = "{" + tmpstr + "}"
123+
124+ def insertAttributeVectorStringList (self , name , attributelist ):
125+ """Insert a named list of string lists"""
126+
127+ listOfLists = []
128+ for stringList in attributelist :
129+ # tmp = map ( lambda x : '"' + x + '"', stringList )
130+ tmpstr = "," .join (stringList )
131+ listOfLists .append ("{" + tmpstr + "}" )
132+ self .contents [name ] = "{" + "," .join (listOfLists ) + "}"
133+
134+ def lookupAttribute (self , name ):
135+ """Check the presence of the given attribute"""
136+
137+ return name in self .contents
138+
139+ def set_expression (self , name , attribute ):
140+ """Insert a named expression attribute"""
141+
142+ self .contents [name ] = str (attribute )
143+
144+ def get_expression (self , name ):
145+ """Get expression corresponding to a named attribute"""
146+
147+ if name in self .contents :
148+ if isinstance (self .contents [name ], int ):
149+ return str (self .contents [name ])
150+ return self .contents [name ]
151+ return ""
152+
153+ def isAttributeList (self , name ):
154+ """Check if the given attribute is of the List type"""
155+ attribute = self .get_expression (name ).strip ()
156+ return attribute .startswith ("{" )
157+
158+ def getListFromExpression (self , name ):
159+ """Get a list of strings from a given expression"""
160+
161+ tempString = self .get_expression (name ).strip ()
162+ listMode = False
163+ if tempString .startswith ("{" ):
164+ tempString = tempString [1 :- 1 ]
165+ listMode = True
166+
167+ tempString = tempString .replace (" " , "" ).replace ("\n " , "" )
168+ if tempString .find ("{" ) < 0 :
169+ if not listMode :
170+ tempString = tempString .replace ('"' , "" )
171+ if not tempString :
172+ return []
173+ return tempString .split ("," )
174+
175+ resultList = []
176+ while tempString :
177+ if tempString .find ("{" ) == 0 :
178+ end = tempString .find ("}" )
179+ resultList .append (tempString [: end + 1 ])
180+ tempString = tempString [end + 1 :]
181+ if tempString .startswith ("," ):
182+ tempString = tempString [1 :]
183+ elif tempString .find ('"' ) == 0 :
184+ end = tempString [1 :].find ('"' )
185+ resultList .append (tempString [1 : end + 1 ])
186+ tempString = tempString [end + 2 :]
187+ if tempString .startswith ("," ):
188+ tempString = tempString [1 :]
189+ else :
190+ end = tempString .find ("," )
191+ if end < 0 :
192+ resultList .append (tempString .replace ('"' , "" ).replace (" " , "" ))
193+ break
194+ else :
195+ resultList .append (tempString [:end ].replace ('"' , "" ).replace (" " , "" ))
196+ tempString = tempString [end + 1 :]
197+
198+ return resultList
199+
200+ def getDictionaryFromSubJDL (self , name ):
201+ """Get a dictionary of the JDL attributes from a subsection"""
202+
203+ tempList = self .get_expression (name )[1 :- 1 ]
204+ resDict = {}
205+ for item in tempList .split (";" ):
206+ if len (item .split ("=" )) == 2 :
207+ resDict [item .split ("=" )[0 ].strip ()] = item .split ("=" )[1 ].strip ().replace ('"' , "" )
208+ else :
209+ return {}
210+
211+ return resDict
212+
213+ def deleteAttribute (self , name ):
214+ """Delete a named attribute"""
215+
216+ if name in self .contents :
217+ del self .contents [name ]
218+ return 1
219+ return 0
220+
221+ def isOK (self ):
222+ """Check the JDL validity - to be defined"""
223+
224+ if self .contents :
225+ return 1
226+ return 0
227+
228+ def asJDL (self ):
229+ """Convert the JDL description into a string"""
230+
231+ result = []
232+ for name , value in sorted (self .contents .items ()):
233+ if value [0 :1 ] == "{" :
234+ result += [4 * " " + name + " = \n " ]
235+ result += [8 * " " + "{\n " ]
236+ strings = value [1 :- 1 ].split ("," )
237+ for st in strings :
238+ result += [12 * " " + st .strip () + ",\n " ]
239+ result [- 1 ] = result [- 1 ][:- 2 ]
240+ result += ["\n " + 8 * " " + "};\n " ]
241+ elif value [0 :1 ] == "[" :
242+ tempad = ClassAd (value )
243+ tempjdl = tempad .asJDL () + ";"
244+ lines = tempjdl .split ("\n " )
245+ result += [4 * " " + name + " = \n " ]
246+ for line in lines :
247+ result += [8 * " " + line + "\n " ]
248+
249+ else :
250+ result += [4 * " " + name + " = " + str (value ) + ";\n " ]
251+ if result :
252+ result [- 1 ] = result [- 1 ][:- 1 ]
253+ return "[ \n " + "" .join (result ) + "\n ]"
254+
255+ def getAttributeString (self , name ):
256+ """Get String type attribute value"""
257+ value = ""
258+ if self .lookupAttribute (name ):
259+ value = self .get_expression (name ).replace ('"' , "" )
260+ return value
261+
262+ def getAttributeInt (self , name ):
263+ """Get Integer type attribute value"""
264+ value = None
265+ if self .lookupAttribute (name ):
266+ try :
267+ value = int (self .get_expression (name ).replace ('"' , "" ))
268+ except Exception :
269+ value = None
270+ return value
271+
272+ def getAttributeBool (self , name ):
273+ """Get Boolean type attribute value"""
274+ if not self .lookupAttribute (name ):
275+ return False
276+
277+ value = self .get_expression (name ).replace ('"' , "" )
278+ return value .lower () == "true"
279+
280+ def getAttributeFloat (self , name ):
281+ """Get Float type attribute value"""
282+ value = None
283+ if self .lookupAttribute (name ):
284+ try :
285+ value = float (self .get_expression (name ).replace ('"' , "" ))
286+ except Exception :
287+ value = None
288+ return value
289+
290+ def getAttributes (self ) -> list [str ]:
291+ """Get the list of all the attribute names
292+
293+ :return: list of names as strings
294+ """
295+ return list (self .contents )
0 commit comments