41
41
from cylc .flow .task_proxy import TaskProxy
42
42
from cylc .flow .wallclock import get_current_time_string
43
43
44
- _XTRIG_FUNCS : dict = {}
44
+ _XTRIG_MOD_CACHE : dict = {}
45
+ _XTRIG_FUNC_CACHE : dict = {}
45
46
46
47
47
48
def _killpg (proc , signal ):
@@ -66,68 +67,86 @@ def _killpg(proc, signal):
66
67
return True
67
68
68
69
69
- def get_func ( func_name , src_dir ):
70
- """Find and return an xtrigger function from a module of the same name .
70
+ def get_xtrig_mod ( mod_name , src_dir ):
71
+ """Find, cache, and return a named xtrigger module .
71
72
72
- These locations are checked in this order:
73
- - <src_dir>/lib/python/
74
- - `$CYLC_PYTHONPATH`
75
- - defined via a `cylc.xtriggers` entry point for an
76
- installed Python package.
73
+ Locations checked in this order:
74
+ - <src_dir>/lib/python (prepend to sys.path)
75
+ - $CYLC_PYTHONPATH (already in sys.path)
76
+ - `cylc.xtriggers` entry point
77
77
78
- Workflow source directory passed in as this is executed in an independent
79
- process in the command pool and therefore doesn't know about the workflow.
78
+ (Check entry point last so users can override with local implementations).
79
+
80
+ Workflow source dir passed in - this executes in an independent subprocess.
81
+
82
+ Raises:
83
+ ImportError, if the module is not found
80
84
81
85
"""
82
- if func_name in _XTRIG_FUNCS :
83
- return _XTRIG_FUNCS [func_name ]
86
+ if mod_name in _XTRIG_MOD_CACHE :
87
+ # Found and cached already.
88
+ return _XTRIG_MOD_CACHE [mod_name ]
84
89
85
90
# First look in <src-dir>/lib/python.
86
91
sys .path .insert (0 , os .path .join (src_dir , 'lib' , 'python' ))
87
- mod_name = func_name
88
92
try :
89
- mod_by_name = __import__ (mod_name , fromlist = [mod_name ])
93
+ _XTRIG_MOD_CACHE [ mod_name ] = __import__ (mod_name , fromlist = [mod_name ])
90
94
except ImportError :
91
- # Look for xtriggers via entry_points for external sources.
92
- # Do this after the lib/python and PYTHONPATH approaches to allow
93
- # users to override entry_point definitions with local/custom
94
- # implementations.
95
+ # Then entry point.
95
96
for entry_point in iter_entry_points ('cylc.xtriggers' ):
96
- if func_name == entry_point .name :
97
- _XTRIG_FUNCS [func_name ] = entry_point .load ()
98
- return _XTRIG_FUNCS [func_name ]
99
-
97
+ if mod_name == entry_point .name :
98
+ _XTRIG_MOD_CACHE [mod_name ] = entry_point .load ()
99
+ return _XTRIG_MOD_CACHE [mod_name ]
100
100
# Still unable to find anything so abort
101
101
raise
102
102
103
- try :
104
- _XTRIG_FUNCS [func_name ] = getattr (mod_by_name , func_name )
105
- except AttributeError :
106
- # Module func_name has no function func_name, nor an entry_point entry.
107
- raise
108
- return _XTRIG_FUNCS [func_name ]
103
+ return _XTRIG_MOD_CACHE [mod_name ]
104
+
105
+
106
+ def get_xtrig_func (mod_name , func_name , src_dir ):
107
+ """Find, cache, and return a function from an xtrigger module.
108
+
109
+ Raises:
110
+ ImportError, if the module is not found
111
+ AttributeError, if the function is not found in the module
112
+
113
+ """
114
+ if (mod_name , func_name ) in _XTRIG_FUNC_CACHE :
115
+ return _XTRIG_FUNC_CACHE [(mod_name , func_name )]
116
+
117
+ mod = get_xtrig_mod (mod_name , src_dir )
118
+
119
+ _XTRIG_FUNC_CACHE [(mod_name , func_name )] = getattr (mod , func_name )
120
+
121
+ return _XTRIG_FUNC_CACHE [(mod_name , func_name )]
109
122
110
123
111
124
def run_function (func_name , json_args , json_kwargs , src_dir ):
112
125
"""Run a Python function in the process pool.
113
126
114
127
func_name(*func_args, **func_kwargs)
115
128
129
+ The function is presumed to be in a module of the same name.
130
+
116
131
Redirect any function stdout to stderr (and workflow log in debug mode).
117
132
Return value printed to stdout as a JSON string - allows use of the
118
133
existing process pool machinery as-is. src_dir is for local modules.
119
134
120
135
"""
121
136
func_args = json .loads (json_args )
122
137
func_kwargs = json .loads (json_kwargs )
138
+
123
139
# Find and import then function.
124
- func = get_func (func_name , src_dir )
140
+ func = get_xtrig_func (func_name , func_name , src_dir )
141
+
125
142
# Redirect stdout to stderr.
126
143
orig_stdout = sys .stdout
127
144
sys .stdout = sys .stderr
128
145
res = func (* func_args , ** func_kwargs )
146
+
129
147
# Restore stdout.
130
148
sys .stdout = orig_stdout
149
+
131
150
# Write function return value as JSON to stdout.
132
151
sys .stdout .write (json .dumps (res ))
133
152
0 commit comments