4
4
# Copyright © 2019, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
5
5
# SPDX-License-Identifier: Apache-2.0
6
6
7
+ """A stateless, memory-resident, high-performance program execution service."""
8
+
7
9
from collections import OrderedDict
8
10
9
11
from .service import Service
10
- from sasctl .core import HTTPError
11
12
12
13
13
14
class MicroAnalyticScore (Service ):
14
- """A stateless, memory-resident, high-performance program execution
15
- service.
15
+ """Micro Analytic Service (MAS) client."""
16
16
17
- """
18
17
_SERVICE_ROOT = '/microanalyticScore'
19
18
20
- def list_modules (self , filter = None ):
21
- params = 'filter={}' .format (filter ) if filter is not None else {}
19
+ @classmethod
20
+ def is_uuid (cls , id ):
21
+ """Check if the ID appears to be a valid MAS id.
22
22
23
- return self .get ('/modules' , params = params )
23
+ Indicates whether `id` appears to be a correctly formatted ID. Does
24
+ **not** check whether a module with `id` actually exists.
24
25
25
- def get_module ( self , module ):
26
- if isinstance ( module , dict ) and all ([ k in module for k in ( 'id' , 'name' )]):
27
- return module
26
+ Parameters
27
+ ----------
28
+ id : str
28
29
29
- try :
30
- # MAS module IDs appear to just be the lower case name.
31
- # Try to find by ID first
32
- return self .get ('/modules/{}' .format (str (
33
- module ).lower ()))
34
- except HTTPError as e :
35
- if e .code == 404 :
36
- pass
37
- else :
38
- raise e
30
+ Returns
31
+ -------
32
+ bool
39
33
40
- # Wasn't able to find by id, try searching by name
41
- results = self .list_modules (filter = 'eq(name, "{}")' .format (module ))
34
+ Notes
35
+ -----
36
+ Overrides the :meth:`Service.is_uuid` method since MAS modules do
37
+ not currently use IDs that are actually UUIDs.
42
38
43
- # Not sure why, but as of 19w04 the filter doesn't seem to work.
44
- for result in results :
45
- if result ['name' ] == str (module ):
46
- return result
39
+ """
40
+ return True
41
+
42
+ list_modules , get_module , update_module , \
43
+ delete_module = Service ._crud_funcs ('/modules' , 'module' )
47
44
48
45
def get_module_step (self , module , step ):
46
+ """Details of a single step in a given module.
47
+
48
+ Parameters
49
+ ----------
50
+ module : str or dict
51
+ Name, id, or dictionary representation of a module
52
+ step : str
53
+ Name of the step
54
+
55
+ Returns
56
+ -------
57
+ RestObj
58
+
59
+ """
49
60
module = self .get_module (module )
50
61
51
62
r = self .get ('/modules/{}/steps/{}' .format (module .id , step ))
52
63
return r
53
64
54
65
def list_module_steps (self , module ):
66
+ """List all steps defined for a module.
67
+
68
+ Parameters
69
+ ----------
70
+ module : str or dict
71
+ Name, id, or dictionary representation of a module
72
+
73
+ Returns
74
+ -------
75
+ list
76
+ List of :class:`.RestObj` instances representing each step.
77
+
78
+ """
55
79
module = self .get_module (module )
56
80
57
- return self .get ('/modules/{}/steps' .format (module .id ))
81
+ steps = self .get ('/modules/{}/steps' .format (module .id ))
82
+ return steps if isinstance (steps , list ) else [steps ]
58
83
59
84
def execute_module_step (self , module , step , return_dict = True , ** kwargs ):
85
+ """Call a module step with the given parameters.
86
+
87
+ Parameters
88
+ ----------
89
+ module : str or dict
90
+ Name, id, or dictionary representation of a module
91
+ step : str
92
+ Name of the step
93
+ return_dict : bool, optional
94
+ Whether the results should be returned as a dictionary instead
95
+ of a tuple
96
+ kwargs : any
97
+ Passed as arguments to the module step
98
+
99
+ Returns
100
+ -------
101
+ any
102
+ Results of the step execution. Returned as a dictionary if
103
+ `return_dict` is True, otherwise returned as a tuple if more
104
+ than one value is returned, otherwise the single value.
105
+
106
+ """
60
107
module_name = module .name if hasattr (module , 'name' ) else str (module )
61
108
module = self .get_module (module )
62
109
@@ -92,7 +139,7 @@ def execute_module_step(self, module, step, return_dict=True, **kwargs):
92
139
93
140
def create_module (self , name = None , description = None , source = None ,
94
141
language = 'python' , scope = 'public' ):
95
- """
142
+ """Create a new module in MAS.
96
143
97
144
Parameters
98
145
----------
@@ -104,9 +151,9 @@ def create_module(self, name=None, description=None, source=None,
104
151
105
152
Returns
106
153
-------
154
+ RestObj
107
155
108
156
"""
109
-
110
157
if source is None :
111
158
raise ValueError ('The `source` parameter is required.' )
112
159
else :
@@ -117,7 +164,8 @@ def create_module(self, name=None, description=None, source=None,
117
164
elif language == 'ds2' :
118
165
t = 'text/vnd.sas.source.ds2'
119
166
else :
120
- raise ValueError ('Unrecognized source code language `%s`.' % language )
167
+ raise ValueError ('Unrecognized source code language `%s`.'
168
+ % language )
121
169
122
170
data = {'id' : name ,
123
171
'type' : t ,
@@ -129,7 +177,9 @@ def create_module(self, name=None, description=None, source=None,
129
177
return r
130
178
131
179
def define_steps (self , module ):
132
- """Defines python methods on a module that automatically call the
180
+ """Map MAS steps to Python methods.
181
+
182
+ Defines python methods on a module that automatically call the
133
183
corresponding MAS steps.
134
184
135
185
Parameters
@@ -161,10 +211,11 @@ def define_steps(self, module):
161
211
type_string = ' # type: ({})' .format (', ' .join (arg_types ))
162
212
163
213
# Method signature
164
- signature = 'def _%s_%s(%s, **kwargs):' % (module .name ,
165
- step .id ,
166
- ', ' .join (a for a
167
- in arguments ))
214
+ signature = 'def _%s_%s(%s, **kwargs):' \
215
+ % (module .name ,
216
+ step .id ,
217
+ ', ' .join (a for a in arguments ))
218
+
168
219
# MAS always lower-cases variable names
169
220
# Since the original Python variables may have a different case,
170
221
# allow kwargs to be used to input alternative caps
@@ -180,7 +231,8 @@ def define_steps(self, module):
180
231
type_string ,
181
232
' """Execute step %s of module %s."""' % (step , module ),
182
233
'\n ' .join ([' %s' % a for a in arg_checks ]),
183
- ' r = execute_module_step(module, step, {})' .format (', ' .join (call_params )),
234
+ ' r = execute_module_step(module, step, {})' .format (
235
+ ', ' .join (call_params )),
184
236
' r.pop("rc", None)' ,
185
237
' r.pop("msg", None)' ,
186
238
' if len(r) == 1:' ,
0 commit comments