Passed
Push — master ( 227024...1d0698 )
by Oleksandr
02:44
created

tabpy.tabpy_tools.rest_client   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 22
eloc 97
dl 0
loc 252
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A RESTServiceClient.get_status() 0 9 1
A RESTServiceClient.remove_endpoint() 0 11 1
A RESTServiceClient.add_endpoint() 0 9 1
A ModelEndpoint.__eq__() 0 4 1
A RESTServiceClient.get_endpoints() 0 18 2
A RESTServiceClient.get_endpoint_upload_destination() 0 15 1
A RESTServiceClient.get_info() 0 3 1
A RESTServiceClient.get_endpoint() 0 15 1
A AliasEndpoint.__init__() 0 3 1
A Endpoint.__new__() 0 10 1
A Endpoint.__eq__() 0 10 1
A RESTServiceClient.set_endpoint() 0 12 1
A RESTServiceClient.__init__() 0 3 1
A ModelEndpoint.__init__() 0 3 1
A RESTServiceClient.set_credentials() 0 14 1
A RESTServiceClient.query() 0 10 3

2 Functions

Rating   Name   Duplication   Size   Complexity  
A to_epoch() 0 2 1
A from_epoch() 0 5 2
1
from .rest import RESTObject, RESTProperty
2
from datetime import datetime
3
4
5
def from_epoch(value):
6
    if isinstance(value, datetime):
7
        return value
8
    else:
9
        return datetime.utcfromtimestamp(value)
10
11
12
def to_epoch(value):
13
    return (value - datetime(1970, 1, 1)).total_seconds()
14
15
16
class Endpoint(RESTObject):
17
    """Represents an endpoint.
18
19
    Note that not every attribute is returned as part of the GET.
20
21
    Attributes
22
    ----------
23
24
    name : str
25
        The name of the endpoint. Valid names include ``[a-zA-Z0-9_\\- ]+``
26
    type : str
27
        The type of endpoint. The types include "alias", "model".
28
    version : int
29
        The version of this endpoint. Initial versions have version on 1. New
30
        versions increment this by 1.
31
    description : str
32
        A human-readable description of the endpoint.
33
    dependencies: list
34
        A list of endpoints that this endpoint depends on.
35
    methods : list
36
        ???
37
    """
38
    name = RESTProperty(str)
39
    type = RESTProperty(str)
40
    version = RESTProperty(int)
41
    description = RESTProperty(str)
42
    dependencies = RESTProperty(list)
43
    methods = RESTProperty(list)
44
    creation_time = RESTProperty(datetime, from_epoch, to_epoch)
45
    last_modified_time = RESTProperty(datetime, from_epoch, to_epoch)
46
    evaluator = RESTProperty(str)
47
    schema_version = RESTProperty(int)
48
    schema = RESTProperty(str)
49
50
    def __new__(cls, **kwargs):
51
        """Dispatch to the appropriate class."""
52
        cls = {
53
            'alias': AliasEndpoint,
54
            'model': ModelEndpoint,
55
        }[kwargs['type']]
56
57
        """return object.__new__(cls, **kwargs)"""
58
        """ modified for Python 3"""
59
        return object.__new__(cls)
60
61
    def __eq__(self, other):
62
        return self.name == other.name and \
63
            self.type == other.type and \
64
            self.version == other.version and \
65
            self.description == other.description and \
66
            self.dependencies == other.dependencies and \
67
            self.methods == other.methods and \
68
            self.evaluator == other.evaluator and \
69
            self.schema_version == other.schema_version and \
70
            self.schema == other.schema
71
72
73
class ModelEndpoint(Endpoint):
74
    """Represents a model endpoint.
75
76
    src_path : str
77
78
        The local file path to the source of this object.
79
80
    required_files : str
81
82
        The local file path to the directory containing the
83
        required files.
84
85
    required_packages : str
86
87
        The local file path to the directory containing the
88
        required packages.
89
90
    """
91
    src_path = RESTProperty(str)
92
    required_files = RESTProperty(list)
93
    required_packages = RESTProperty(list)
94
    required_packages_dst_path = RESTProperty(str)
95
96
    def __init__(self, **kwargs):
97
        super().__init__(**kwargs)
98
        self.type = 'model'
99
100
    def __eq__(self, other):
101
        return super().__eq__(other) and \
102
            self.required_files == other.required_files and \
103
            self.required_packages == other.required_packages
104
105
106
class AliasEndpoint(Endpoint):
107
    """Represents an alias Endpoint.
108
109
    target : str
110
111
        The endpoint that this is an alias for.
112
113
    """
114
    target = RESTProperty(str)
115
116
    def __init__(self, **kwargs):
117
        super().__init__(**kwargs)
118
        self.type = 'alias'
119
120
121
class RESTServiceClient(object):
122
    """A thin client for the REST Service."""
123
    def __init__(self, service_client):
124
        self.service_client = service_client
125
        self.query_timeout = None
126
127
    def get_info(self):
128
        """Returns the /info"""
129
        return self.service_client.GET('info')
130
131
    def query(self, name, *args, **kwargs):
132
        """Performs a query. Either specify *args or **kwargs, not both.
133
        Respects query_timeout."""
134
        if args and kwargs:
135
            raise ValueError(
136
                'Mixing of keyword arguments and positional arguments when '
137
                'querying an endpoint is not supported.')
138
        return self.service_client.POST('query/' + name,
139
                                        data={'data': args or kwargs},
140
                                        timeout=self.query_timeout)
141
142
    def get_endpoint_upload_destination(self):
143
        """Returns a dict representing where endpoint data should be uploaded.
144
145
        Returns
146
        -------
147
        dict
148
            Keys include:
149
            * path: a local file path.
150
151
        Note: In the future, other paths and parameters may be supported.
152
153
        Note: At this time, the response should not change over time.
154
        """
155
        return self.service_client.GET(
156
            'configurations/endpoint_upload_destination')
157
158
    def get_endpoints(self, type=None):
159
        """Returns endpoints from the management API.
160
161
        Parameters
162
        ----------
163
164
        type : str
165
            The type of endpoint to return. None will include all endpoints.
166
            Other options are 'model' and 'alias'.
167
        """
168
        result = {}
169
        for name, attrs in self.service_client.GET(
170
                'endpoints',
171
                {'type': type}).items():
172
            endpoint = Endpoint.from_json(attrs)
173
            endpoint.name = name
174
            result[name] = endpoint
175
        return result
176
177
    def get_endpoint(self, endpoint_name):
178
        """Returns an endpoints from the management API given its name.
179
180
        Parameters
181
        ----------
182
183
        endpoint_name : str
184
185
            The name of the endpoint.
186
        """
187
        ((name, attrs),) = self.service_client.GET(
188
            'endpoints/' + endpoint_name).items()
189
        endpoint = Endpoint.from_json(attrs)
190
        endpoint.name = name
191
        return endpoint
192
193
    def add_endpoint(self, endpoint):
194
        """Adds an endpoint through the management API.
195
196
        Parameters
197
        ----------
198
199
        endpoint : Endpoint
200
        """
201
        return self.service_client.POST('endpoints', endpoint.to_json())
202
203
    def set_endpoint(self, endpoint):
204
        """Updates an endpoint through the management API.
205
206
        Parameters
207
        ----------
208
209
        endpoint : Endpoint
210
211
            The endpoint to update.
212
        """
213
        return self.service_client.PUT(
214
            'endpoints/' + endpoint.name, endpoint.to_json())
215
216
    def remove_endpoint(self, endpoint_name):
217
        """Deletes an endpoint through the management API.
218
219
        Parameters
220
        ----------
221
222
        endpoint_name : str
223
224
            The endpoint to delete.
225
        """
226
        self.service_client.DELETE('endpoints/'+endpoint_name)
227
228
    def get_status(self):
229
        """Returns the status of the server.
230
231
        Returns
232
        -------
233
234
        dict
235
        """
236
        return self.service_client.GET('status')
237
238
    def set_credentials(self, username, password):
239
        '''
240
        Set credentials for all the TabPy client-server communication
241
        where client is tabpy-tools and server is tabpy-server.
242
243
        Parameters
244
        ----------
245
        username : str
246
            User name (login). Username is case insensitive.
247
248
        password : str
249
            Password in plain text.
250
        '''
251
        self.service_client.set_credentials(username, password)
252