Passed
Pull Request — master (#644)
by
unknown
21:04 queued 04:15
created

tabpy.tabpy_tools.rest_client   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 253
Duplicated Lines 0 %

Test Coverage

Coverage 80.26%

Importance

Changes 0
Metric Value
wmc 22
eloc 90
dl 0
loc 253
ccs 61
cts 76
cp 0.8026
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 5 1
A RESTServiceClient.get_endpoints() 0 16 2
A RESTServiceClient.get_endpoint_upload_destination() 0 14 1
A RESTServiceClient.get_info() 0 3 1
A RESTServiceClient.get_endpoint() 0 14 1
A AliasEndpoint.__init__() 0 3 1
A Endpoint.__eq__() 0 11 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
A RESTServiceClient.set_endpoint() 0 11 1
A Endpoint.__new__() 0 7 1

2 Functions

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