DIRAC 9.0.0a66__py3-none-any.whl → 9.0.0a68__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 (38) hide show
  1. DIRAC/ConfigurationSystem/Client/Helpers/Resources.py +11 -43
  2. DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py +0 -16
  3. DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +1 -1
  4. DIRAC/Core/Security/IAMService.py +4 -3
  5. DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
  6. DIRAC/Core/Utilities/DErrno.py +1 -1
  7. DIRAC/Core/Utilities/JDL.py +1 -195
  8. DIRAC/Core/Utilities/List.py +1 -127
  9. DIRAC/Core/Utilities/ReturnValues.py +2 -2
  10. DIRAC/Core/Utilities/StateMachine.py +12 -178
  11. DIRAC/Core/Utilities/TimeUtilities.py +10 -253
  12. DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
  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/Workflow/Modules/test/Test_Modules.py +5 -0
  18. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +2 -0
  19. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
  20. DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
  21. DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -93
  22. DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
  23. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +4 -2
  24. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +21 -5
  25. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
  26. DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -199
  27. DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +1 -63
  28. DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
  29. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -5
  30. DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
  31. {dirac-9.0.0a66.dist-info → dirac-9.0.0a68.dist-info}/METADATA +2 -2
  32. {dirac-9.0.0a66.dist-info → dirac-9.0.0a68.dist-info}/RECORD +36 -38
  33. DIRAC/Core/Utilities/test/Test_List.py +0 -150
  34. DIRAC/Core/Utilities/test/Test_Time.py +0 -88
  35. {dirac-9.0.0a66.dist-info → dirac-9.0.0a68.dist-info}/WHEEL +0 -0
  36. {dirac-9.0.0a66.dist-info → dirac-9.0.0a68.dist-info}/entry_points.txt +0 -0
  37. {dirac-9.0.0a66.dist-info → dirac-9.0.0a68.dist-info}/licenses/LICENSE +0 -0
  38. {dirac-9.0.0a66.dist-info → dirac-9.0.0a68.dist-info}/top_level.txt +0 -0
@@ -1,127 +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, TypeVar
7
- from collections.abc import Iterable
8
-
9
- T = TypeVar("T")
10
-
11
-
12
- def uniqueElements(aList: list) -> list:
13
- """Utility to retrieve list of unique elements in a list (order is kept)."""
14
-
15
- # Use dict.fromkeys instead of set ensure the order is preserved
16
- return list(dict.fromkeys(aList))
17
-
18
-
19
- def appendUnique(aList: list, anObject: Any):
20
- """Append to list if object does not exist.
21
-
22
- :param aList: list of elements
23
- :param anObject: object you want to append
24
- """
25
- if anObject not in aList:
26
- aList.append(anObject)
27
-
28
-
29
- def fromChar(inputString: str, sepChar: str = ","):
30
- """Generates a list splitting a string by the required character(s)
31
- resulting string items are stripped and empty items are removed.
32
-
33
- :param inputString: list serialised to string
34
- :param sepChar: separator
35
- :return: list of strings or None if sepChar has a wrong type
36
- """
37
- # to prevent getting an empty String as argument
38
- if not (isinstance(inputString, str) and isinstance(sepChar, str) and sepChar):
39
- return None
40
- return [fieldString.strip() for fieldString in inputString.split(sepChar) if len(fieldString.strip()) > 0]
41
-
42
-
43
- def randomize(aList: Iterable[T]) -> list[T]:
44
- """Return a randomly sorted list.
45
-
46
- :param aList: list to permute
47
- """
48
- tmpList = list(aList)
49
- random.shuffle(tmpList)
50
- return tmpList
51
-
52
-
53
- def pop(aList, popElement):
54
- """Pop the first element equal to popElement from the list.
55
-
56
- :param aList: list
57
- :type aList: python:list
58
- :param popElement: element to pop
59
- """
60
- if popElement in aList:
61
- return aList.pop(aList.index(popElement))
62
-
63
-
64
- def stringListToString(aList: list) -> str:
65
- """This function is used for making MySQL queries with a list of string elements.
66
-
67
- :param aList: list to be serialized to string for making queries
68
- """
69
- return ",".join(f"'{x}'" for x in aList)
70
-
71
-
72
- def intListToString(aList: list) -> str:
73
- """This function is used for making MySQL queries with a list of int elements.
74
-
75
- :param aList: list to be serialized to string for making queries
76
- """
77
- return ",".join(str(x) for x in aList)
78
-
79
-
80
- def getChunk(aList: list, chunkSize: int):
81
- """Generator yielding chunk from a list of a size chunkSize.
82
-
83
- :param aList: list to be splitted
84
- :param chunkSize: lenght of one chunk
85
- :raise: StopIteration
86
-
87
- Usage:
88
-
89
- >>> for chunk in getChunk( aList, chunkSize=10):
90
- process( chunk )
91
-
92
- """
93
- chunkSize = int(chunkSize)
94
- for i in range(0, len(aList), chunkSize):
95
- yield aList[i : i + chunkSize]
96
-
97
-
98
- def breakListIntoChunks(aList: list, chunkSize: int):
99
- """This function takes a list as input and breaks it into list of size 'chunkSize'.
100
- It returns a list of lists.
101
-
102
- :param aList: list of elements
103
- :param chunkSize: len of a single chunk
104
- :return: list of lists of length of chunkSize
105
- :raise: RuntimeError if numberOfFilesInChunk is less than 1
106
- """
107
- if chunkSize < 1:
108
- raise RuntimeError("chunkSize cannot be less than 1")
109
- if isinstance(aList, (set, dict, tuple, {}.keys().__class__, {}.items().__class__, {}.values().__class__)):
110
- aList = list(aList)
111
- return [chunk for chunk in getChunk(aList, chunkSize)]
112
-
113
-
114
- def getIndexInList(anItem: Any, aList: list) -> int:
115
- """Return the index of the element x in the list l
116
- or sys.maxint if it does not exist
117
-
118
- :param anItem: element to look for
119
- :param aList: list to look into
120
-
121
- :return: the index or sys.maxint
122
- """
123
- # try:
124
- if anItem in aList:
125
- return aList.index(anItem)
126
- else:
127
- return sys.maxsize
1
+ from DIRACCommon.Core.Utilities.List import * # noqa: F401,F403
@@ -1,10 +1,10 @@
1
1
  """Backward compatibility wrapper - moved to DIRACCommon
2
2
 
3
- This module has been moved to DIRACCommon.Utils.ReturnValues to avoid
3
+ This module has been moved to DIRACCommon.Core.Utilities.ReturnValues to avoid
4
4
  circular dependencies and allow DiracX to use these utilities without
5
5
  triggering DIRAC's global state initialization.
6
6
 
7
7
  All exports are maintained for backward compatibility.
8
8
  """
9
9
  # Re-export everything from DIRACCommon for backward compatibility
10
- from DIRACCommon.Utils.ReturnValues import * # noqa: F401, F403
10
+ from DIRACCommon.Core.Utilities.ReturnValues import * # noqa: F401, F403
@@ -1,185 +1,19 @@
1
- """ StateMachine
1
+ """Backward compatibility wrapper - moved to DIRACCommon
2
2
 
3
- This module contains the basic blocks to build a state machine (State and StateMachine)
4
- """
5
- from DIRAC import S_OK, S_ERROR, gLogger
6
-
7
-
8
- class State:
9
- """
10
- State class that represents a single step on a StateMachine, with all the
11
- possible transitions, the default transition and an ordering level.
12
-
13
-
14
- examples:
15
- >>> s0 = State(100)
16
- >>> s1 = State(0, ['StateName1', 'StateName2'], defState='StateName1')
17
- >>> s2 = State(0, ['StateName1', 'StateName2'])
18
- # this example is tricky. The transition rule says that will go to
19
- # nextState, e.g. 'StateNext'. But, it is not on the stateMap, and there
20
- # is no default defined, so it will end up going to StateNext anyway. You
21
- # must be careful while defining states and their stateMaps and defaults.
22
- """
23
-
24
- def __init__(self, level, stateMap=None, defState=None):
25
- """
26
- :param int level: each state is mapped to an integer, which is used to sort the states according to that integer.
27
- :param list stateMap: it is a list (of strings) with the reachable states from this particular status.
28
- If not defined, we assume there are no restrictions.
29
- :param str defState: default state used in case the next state is not in stateMap (not defined or simply not there).
30
- """
31
-
32
- self.level = level
33
- self.stateMap = stateMap if stateMap else []
34
- self.default = defState
35
-
36
- def transitionRule(self, nextState):
37
- """
38
- Method that selects next state, knowing the default and the transitions
39
- map, and the proposed next state. If <nextState> is in stateMap, goes there.
40
- If not, then goes to <self.default> if any. Otherwise, goes to <nextState>
41
- anyway.
42
-
43
- examples:
44
- >>> s0.transitionRule('nextState')
45
- 'nextState'
46
- >>> s1.transitionRule('StateName2')
47
- 'StateName2'
48
- >>> s1.transitionRule('StateNameNotInMap')
49
- 'StateName1'
50
- >>> s2.transitionRule('StateNameNotInMap')
51
- 'StateNameNotInMap'
52
-
53
- :param str nextState: name of the state in the stateMap
54
- :return: state name
55
- :rtype: str
56
- """
57
-
58
- # If next state is on the list of next states, go ahead.
59
- if nextState in self.stateMap:
60
- return nextState
61
-
62
- # If not, calculate defaultState:
63
- # if there is a default, that one
64
- # otherwise is nextState (states with empty list have no movement restrictions)
65
- defaultNext = self.default if self.default else nextState
66
- return defaultNext
67
-
68
-
69
- class StateMachine:
70
- """
71
- StateMachine class that represents the whole state machine with all transitions.
72
-
73
- examples:
74
- >>> sm0 = StateMachine()
75
- >>> sm1 = StateMachine(state = 'Active')
76
-
77
- :param state: current state of the StateMachine, could be None if we do not use the
78
- StateMachine to calculate transitions. Beware, it is not checked if the
79
- state is on the states map !
80
- :type state: None or str
81
-
82
- """
3
+ This module has been moved to DIRACCommon.Core.Utilities.StateMachine to avoid
4
+ circular dependencies and allow DiracX to use these utilities without
5
+ triggering DIRAC's global state initialization.
83
6
 
84
- def __init__(self, state=None):
85
- """
86
- Constructor.
87
- """
88
-
89
- self.state = state
90
- # To be overwritten by child classes, unless you like Nirvana state that much.
91
- self.states = {"Nirvana": State(100)}
92
-
93
- def getLevelOfState(self, state):
94
- """
95
- Given a state name, it returns its level (integer), which defines the hierarchy.
7
+ All exports are maintained for backward compatibility.
8
+ """
9
+ # Re-export everything from DIRACCommon for backward compatibility
10
+ from DIRACCommon.Core.Utilities.StateMachine import * # noqa: F401, F403
96
11
 
97
- >>> sm0.getLevelOfState('Nirvana')
98
- 100
99
- >>> sm0.getLevelOfState('AnotherState')
100
- -1
12
+ from DIRAC import gLogger
101
13
 
102
- :param str state: name of the state, it should be on <self.states> key set
103
- :return: `int` || -1 (if not in <self.states>)
104
- """
105
14
 
106
- if state not in self.states:
107
- return -1
108
- return self.states[state].level
15
+ class StateMachine(StateMachine): # noqa: F405 pylint: disable=function-redefined
16
+ """Backward compatibility wrapper - moved to DIRACCommon"""
109
17
 
110
18
  def setState(self, candidateState, noWarn=False):
111
- """Makes sure the state is either None or known to the machine, and that it is a valid state to move into.
112
- Final states are also checked.
113
-
114
- examples:
115
- >>> sm0.setState(None)['OK']
116
- True
117
- >>> sm0.setState('Nirvana')['OK']
118
- True
119
- >>> sm0.setState('AnotherState')['OK']
120
- False
121
-
122
- :param state: state which will be set as current state of the StateMachine
123
- :type state: None or str
124
- :return: S_OK || S_ERROR
125
- """
126
- if candidateState == self.state:
127
- return S_OK(candidateState)
128
-
129
- if not candidateState:
130
- self.state = candidateState
131
- elif candidateState in self.states:
132
- if not self.states[self.state].stateMap:
133
- if not noWarn:
134
- gLogger.warn("Final state, won't move", f"({self.state}, asked to move to {candidateState})")
135
- return S_OK(self.state)
136
- if candidateState not in self.states[self.state].stateMap:
137
- gLogger.warn(f"Can't move from {self.state} to {candidateState}, choosing a good one")
138
- result = self.getNextState(candidateState)
139
- if not result["OK"]:
140
- return result
141
- self.state = result["Value"]
142
- # If the StateMachine does not accept the candidate, return error message
143
- else:
144
- return S_ERROR(f"setState: {candidateState!r} is not a valid state")
145
-
146
- return S_OK(self.state)
147
-
148
- def getStates(self):
149
- """
150
- Returns all possible states in the state map
151
-
152
- examples:
153
- >>> sm0.getStates()
154
- [ 'Nirvana' ]
155
-
156
- :return: list(stateNames)
157
- """
158
-
159
- return list(self.states)
160
-
161
- def getNextState(self, candidateState):
162
- """
163
- Method that gets the next state, given the proposed transition to candidateState.
164
- If candidateState is not on the state map <self.states>, it is rejected. If it is
165
- not the case, we have two options: if <self.state> is None, then the next state
166
- will be <candidateState>. Otherwise, the current state is using its own
167
- transition rule to decide.
168
-
169
- examples:
170
- >>> sm0.getNextState(None)
171
- S_OK(None)
172
- >>> sm0.getNextState('NextState')
173
- S_OK('NextState')
174
-
175
- :param str candidateState: name of the next state
176
- :return: S_OK(nextState) || S_ERROR
177
- """
178
- if candidateState not in self.states:
179
- return S_ERROR(f"getNextState: {candidateState!r} is not a valid state")
180
-
181
- # FIXME: do we need this anymore ?
182
- if self.state is None:
183
- return S_OK(candidateState)
184
-
185
- return S_OK(self.states[self.state].transitionRule(candidateState))
19
+ return super().setState(candidateState, noWarn, logger_warn=gLogger.warn)
@@ -1,260 +1,17 @@
1
- """
2
- DIRAC TimeUtilities module
3
- Support for basic Date and Time operations
4
- based on system datetime module.
5
-
6
- It provides common interface to UTC timestamps,
7
- converter to string types and back.
8
-
9
- Useful timedelta constant are also provided to
10
- define time intervals.
11
-
12
- Notice: datetime.timedelta objects allow multiplication and division by interger
13
- but not by float. Thus:
14
-
15
- - DIRAC.TimeUtilities.second * 1.5 is not allowed
16
- - DIRAC.TimeUtilities.second * 3 / 2 is allowed
1
+ """Backward compatibility wrapper - moved to DIRACCommon
17
2
 
18
- An timeInterval class provides a method to check
19
- if a give datetime is in the defined interval.
3
+ This module has been moved to DIRACCommon.Core.Utilities.TimeUtilities to avoid
4
+ circular dependencies and allow DiracX to use these utilities without
5
+ triggering DIRAC's global state initialization.
20
6
 
7
+ All exports are maintained for backward compatibility.
21
8
  """
22
- import datetime
23
- import sys
24
- import time
25
-
26
- from DIRAC import gLogger
27
-
28
- # Some useful constants for time operations
29
- microsecond = datetime.timedelta(microseconds=1)
30
- second = datetime.timedelta(seconds=1)
31
- minute = datetime.timedelta(minutes=1)
32
- hour = datetime.timedelta(hours=1)
33
- day = datetime.timedelta(days=1)
34
- week = datetime.timedelta(days=7)
35
-
36
-
37
- def timeThis(method):
38
- """Function to be used as a decorator for timing other functions/methods"""
39
-
40
- def timed(*args, **kw):
41
- """What actually times"""
42
- ts = time.time()
43
- result = method(*args, **kw)
44
- if sys.stdout.isatty():
45
- return result
46
- te = time.time()
47
-
48
- pre = datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC ")
49
-
50
- try:
51
- pre += args[0].log.getName() + "/" + args[0].log.getSubName() + " TIME: " + args[0].transString
52
- except AttributeError:
53
- try:
54
- pre += args[0].log.getName() + " TIME: " + args[0].transString
55
- except AttributeError:
56
- try:
57
- pre += args[0].log.getName() + "/" + args[0].log.getSubName() + " TIME: "
58
- except AttributeError:
59
- pre += "TIME: "
60
- except IndexError:
61
- pre += "TIME: "
62
-
63
- argsLen = ""
64
- if args:
65
- try:
66
- if isinstance(args[1], (list, dict)):
67
- argsLen = f"arguments len: {len(args[1])}"
68
- except IndexError:
69
- if kw:
70
- try:
71
- if isinstance(list(list(kw.items())[0])[1], (list, dict)):
72
- argsLen = f"arguments len: {len(list(list(kw.items())[0])[1])}"
73
- except IndexError:
74
- argsLen = ""
75
-
76
- gLogger.info(f"{pre} Exec time ===> function {method.__name__!r} {argsLen} -> {te - ts:2.2f} sec")
77
- return result
78
-
79
- return timed
80
-
81
-
82
- def toEpoch(dateTimeObject=None):
83
- """
84
- Get seconds since epoch. Accepts datetime or date objects
85
- """
86
- return toEpochMilliSeconds(dateTimeObject) // 1000
9
+ from functools import partial
87
10
 
11
+ # Re-export everything from DIRACCommon for backward compatibility
12
+ from DIRACCommon.Core.Utilities.TimeUtilities import * # noqa: F401, F403
88
13
 
89
- def toEpochMilliSeconds(dateTimeObject=None):
90
- """
91
- Get milliseconds since epoch
92
- """
93
- if dateTimeObject is None:
94
- dateTimeObject = datetime.datetime.utcnow()
95
- if dateTimeObject.resolution == datetime.timedelta(days=1):
96
- # Add time information corresponding to midnight UTC if it's a datetime.date
97
- dateTimeObject = datetime.datetime.combine(
98
- dateTimeObject, datetime.time.min.replace(tzinfo=datetime.timezone.utc)
99
- )
100
- posixTime = dateTimeObject.replace(tzinfo=datetime.timezone.utc).timestamp()
101
- return int(posixTime * 1000)
102
-
103
-
104
- def fromEpoch(epoch):
105
- """
106
- Get datetime object from epoch
107
- """
108
- # Check if the timestamp is in milliseconds
109
- if epoch > 10**17: # nanoseconds
110
- epoch /= 1000**3
111
- elif epoch > 10**14: # microseconds
112
- epoch /= 1000**2
113
- elif epoch > 10**11: # milliseconds
114
- epoch /= 1000
115
- return datetime.datetime.utcfromtimestamp(epoch)
116
-
117
-
118
- def toString(myDate=None):
119
- """
120
- Convert to String
121
- if argument type is neither _dateTimeType, _dateType, nor _timeType
122
- the current dateTime converted to String is returned instead
123
-
124
- Notice: datetime.timedelta are converted to strings using the format:
125
- [day] days [hour]:[min]:[sec]:[microsec]
126
- where hour, min, sec, microsec are always positive integers,
127
- and day carries the sign.
128
- To keep internal consistency we are using:
129
- [hour]:[min]:[sec]:[microsec]
130
- where min, sec, microsec are always positive integers and hour carries the sign.
131
- """
132
- if isinstance(myDate, datetime.date):
133
- return str(myDate)
134
-
135
- elif isinstance(myDate, datetime.time):
136
- return "%02d:%02d:%02d.%06d" % (
137
- myDate.days * 24 + myDate.seconds / 3600,
138
- myDate.seconds % 3600 / 60,
139
- myDate.seconds % 60,
140
- myDate.microseconds,
141
- )
142
- else:
143
- return toString(datetime.datetime.utcnow())
144
-
145
-
146
- def fromString(myDate=None):
147
- """
148
- Convert date/time/datetime String back to appropriated objects
149
-
150
- The format of the string it is assume to be that returned by toString method.
151
- See notice on toString method
152
- On Error, return None
153
-
154
- :param myDate: the date string to be converted
155
- :type myDate: str or datetime.datetime
156
- """
157
- if isinstance(myDate, datetime.datetime):
158
- return myDate
159
- if isinstance(myDate, str):
160
- if myDate.find(" ") > 0:
161
- dateTimeTuple = myDate.split(" ")
162
- dateTuple = dateTimeTuple[0].split("-")
163
- try:
164
- return datetime.datetime(year=dateTuple[0], month=dateTuple[1], day=dateTuple[2]) + fromString(
165
- dateTimeTuple[1]
166
- )
167
- # return datetime.datetime.utcnow().combine( fromString( dateTimeTuple[0] ),
168
- # fromString( dateTimeTuple[1] ) )
169
- except Exception:
170
- try:
171
- return datetime.datetime(
172
- year=int(dateTuple[0]), month=int(dateTuple[1]), day=int(dateTuple[2])
173
- ) + fromString(dateTimeTuple[1])
174
- except ValueError:
175
- return None
176
- # return datetime.datetime.utcnow().combine( fromString( dateTimeTuple[0] ),
177
- # fromString( dateTimeTuple[1] ) )
178
- elif myDate.find(":") > 0:
179
- timeTuple = myDate.replace(".", ":").split(":")
180
- try:
181
- if len(timeTuple) == 4:
182
- return datetime.timedelta(
183
- hours=int(timeTuple[0]),
184
- minutes=int(timeTuple[1]),
185
- seconds=int(timeTuple[2]),
186
- microseconds=int(timeTuple[3]),
187
- )
188
- elif len(timeTuple) == 3:
189
- try:
190
- return datetime.timedelta(
191
- hours=int(timeTuple[0]),
192
- minutes=int(timeTuple[1]),
193
- seconds=int(timeTuple[2]),
194
- microseconds=0,
195
- )
196
- except ValueError:
197
- return None
198
- else:
199
- return None
200
- except Exception:
201
- return None
202
- elif myDate.find("-") > 0:
203
- dateTuple = myDate.split("-")
204
- try:
205
- return datetime.date(int(dateTuple[0]), int(dateTuple[1]), int(dateTuple[2]))
206
- except Exception:
207
- return None
208
-
209
- return None
210
-
211
-
212
- class timeInterval:
213
- """
214
- Simple class to define a timeInterval object able to check if a given
215
- dateTime is inside
216
- """
217
-
218
- def __init__(self, initialDateTime, intervalTimeDelta):
219
- """
220
- Initialization method, it requires the initial dateTime and the
221
- timedelta that define the limits.
222
- The upper limit is not included thus it is [begin,end)
223
- If not properly initialized an error flag is set, and subsequent calls
224
- to any method will return None
225
- """
226
- if not isinstance(initialDateTime, datetime.datetime) or not isinstance(intervalTimeDelta, datetime.timedelta):
227
- self.__error = True
228
- return None
229
- self.__error = False
230
- if intervalTimeDelta.days < 0:
231
- self.__startDateTime = initialDateTime + intervalTimeDelta
232
- self.__endDateTime = initialDateTime
233
- else:
234
- self.__startDateTime = initialDateTime
235
- self.__endDateTime = initialDateTime + intervalTimeDelta
236
-
237
- def includes(self, myDateTime):
238
- """ """
239
- if self.__error:
240
- return None
241
- if not isinstance(myDateTime, datetime.datetime):
242
- return None
243
- if myDateTime < self.__startDateTime:
244
- return False
245
- if myDateTime >= self.__endDateTime:
246
- return False
247
- return True
248
-
249
-
250
- def queryTime(f):
251
- """Decorator to measure the function call time"""
14
+ from DIRAC import gLogger
252
15
 
253
- def measureQueryTime(*args, **kwargs):
254
- start = time.time()
255
- result = f(*args, **kwargs)
256
- if result["OK"] and "QueryTime" not in result:
257
- result["QueryTime"] = time.time() - start
258
- return result
259
16
 
260
- return measureQueryTime
17
+ timeThis = partial(timeThis, logger_info=gLogger.info)
@@ -19,9 +19,6 @@ def jdl_monkey_business(monkeypatch):
19
19
  monkeypatch.setattr("DIRAC.Core.Base.API.getSites", lambda: S_OK(["LCG.IN2P3.fr"]))
20
20
  monkeypatch.setattr("DIRAC.WorkloadManagementSystem.Utilities.JobModel.getSites", lambda: S_OK(["LCG.IN2P3.fr"]))
21
21
  monkeypatch.setattr("DIRAC.Interfaces.API.Job.getDIRACPlatforms", lambda: S_OK("x86_64-slc6-gcc49-opt"))
22
- monkeypatch.setattr(
23
- "DIRAC.WorkloadManagementSystem.Utilities.JobModel.getDIRACPlatforms", lambda: S_OK("x86_64-slc6-gcc49-opt")
24
- )
25
22
  yield
26
23
 
27
24
 
@@ -16,6 +16,7 @@ from sqlalchemy import (
16
16
  Enum,
17
17
  Float,
18
18
  ForeignKey,
19
+ Index,
19
20
  Integer,
20
21
  MetaData,
21
22
  SmallInteger,
@@ -85,6 +86,7 @@ fts3JobTable = Table(
85
86
  Column("error", String(2048)),
86
87
  Column("status", Enum(*FTS3Job.ALL_STATES), server_default=FTS3Job.INIT_STATE, index=True),
87
88
  Column("assignment", String(255), server_default=None),
89
+ Index("idx_jobs_lastupdate_assignment", "lastUpdate", "assignment"),
88
90
  mysql_engine="InnoDB",
89
91
  )
90
92
 
@@ -110,6 +112,7 @@ fts3OperationTable = Table(
110
112
  Column("error", String(1024)),
111
113
  Column("type", String(255)),
112
114
  Column("assignment", String(255), server_default=None),
115
+ Index("idx_operations_lastupdate_assignment", "lastUpdate", "assignment"),
113
116
  mysql_engine="InnoDB",
114
117
  )
115
118
 
@@ -6,6 +6,7 @@ integration tests (Test_ReqDB.py)
6
6
  # pylint: disable=invalid-name,wrong-import-position
7
7
  import time
8
8
 
9
+ import pytest
9
10
 
10
11
  from DIRAC.RequestManagementSystem.Client.Request import Request
11
12
  from DIRAC.RequestManagementSystem.Client.Operation import Operation
@@ -42,6 +43,7 @@ def test_stress(reqDB):
42
43
  assert delete["OK"], delete
43
44
 
44
45
 
46
+ @pytest.mark.slow
45
47
  def test_stressBulk(reqDB):
46
48
  """stress test bulk"""
47
49
 
@@ -151,7 +151,7 @@ class RucioFileCatalogClient(FileCatalogClientBase):
151
151
  self.authHost = options.get("AuthHost", None)
152
152
  self.caCertPath = Locations.getCAsLocation()
153
153
  try:
154
- sLog.info(f"Logging in with a proxy located at: {self.proxyPath}")
154
+ sLog.debug(f"Logging in with a proxy located at: {self.proxyPath}")
155
155
  sLog.debug("account: ", self.username)
156
156
  sLog.debug("rucio host: ", self.rucioHost)
157
157
  sLog.debug("auth host: ", self.authHost)
@@ -25,7 +25,7 @@ while True:
25
25
  if os.path.isfile(stopFile):
26
26
  os.remove(stopFile)
27
27
  break
28
- if (time.time() - start) > 30:
28
+ if (time.time() - start) > 5:
29
29
  break
30
30
  print("End job", jobNumber, time.time())
31
31
  """
@@ -262,6 +262,7 @@ def test_executeJob_wholeNode8(createAndDelete):
262
262
  assert "Not enough processors" in submissionResult["Message"]
263
263
 
264
264
 
265
+ @pytest.mark.slow
265
266
  def test_executeJob_submitAndStop(createAndDelete):
266
267
  time.sleep(0.5)
267
268