Skip to content

Commit 215ee58

Browse files
authored
Merge pull request #23 from DevoInc/release-next
Release next to master, v 1.4
2 parents 407db69 + f00dde0 commit 215ee58

File tree

10 files changed

+196
-101
lines changed

10 files changed

+196
-101
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,8 @@ ENV/
108108
.mypy_cache/
109109

110110
*~
111-
.DS_Store
111+
.DS_Store
112+
113+
#Visual Code Studio
114+
.vscode/
115+
devo.json

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [1.4.0]
8+
#### Added
9+
* Allow the parameters user, application name and comment to queries
10+
* Add tests (test_pragmas and test_pragmas test_pragmas_not_comment_free) in the query.py file.
11+
12+
#### Fixed
13+
* Problems when API CAll query has not "to", now added be default "now()" if not to in no stream mode
714

815
## [1.3.1] - 2018-12-04
916
#### Fixed
@@ -17,7 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1724

1825
#### Fixed
1926
* ConnectionError in python 2
20-
* tests of Sender
27+
* tests of Sender
2128
* Close order of API/Buffer
2229

2330
#### Changed

CONTRIBUTORS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
- Ricardo Moya
55
- Javier López
66
- Juan Manuel Cristóbal
7-
- Daniel Alonso
7+
- Daniel Alonso
8+
- Jorge Garcia
9+
- Ovidiu Mircea

devo/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__description__ = 'Devo Python Library.'
22
__url__ = 'http://www.devo.com'
3-
__version__ = "1.3.1"
3+
__version__ = "1.4.0"
44
__author__ = 'Devo'
55
__author_email__ = 'support@devo.com'
66
__license__ = 'MIT'

devo/api/client.py

Lines changed: 93 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
import json
77
import socket
88
import ssl
9-
import requests
109
import sys
10+
import requests
1111
from devo.common import DateParser, Buffer
1212

1313
PY3 = sys.version_info[0] > 2
1414

1515

1616
class DevoClientException(Exception):
1717
""" Default Devo Client Exception """
18-
pass
1918

2019

2120
if not PY3:
@@ -25,10 +24,12 @@ def __init__(self, *args, **kwargs): # real signature unknown
2524
pass
2625

2726

28-
class Client(object):
27+
class Client:
2928
"""
3029
The Devo SERach REst Api main class
3130
"""
31+
CLIENT_DEFAULT_APP_NAME = 'python-sdk-app'
32+
CLIENT_DEFAULT_USER = 'python-sdk-user'
3233
URL_AWS_EU = 'https://api-eu.logtrust.com'
3334
URL_VDC = 'https://spainapi.logtrust.com'
3435
URL_AWS_USA = 'https://api-us.logtrust.com'
@@ -44,11 +45,11 @@ def __init__(self, *args, **kwargs):
4445
:param buffer: Buffer object, if want another diferent queue
4546
"""
4647
self.time_start = int(round(time.time() * 1000))
47-
if len(args) is 3:
48+
if len(args) == 3:
4849
self.key = args[0]
4950
self.secret = args[1]
5051
url = args[2]
51-
elif len(args) is 0:
52+
elif not args:
5253
self.key = kwargs.get("key",
5354
kwargs.get("api_key",
5455
kwargs.get("apiKey", None)))
@@ -65,9 +66,12 @@ def __init__(self, *args, **kwargs):
6566
"3 arguments: key, secret and url, "
6667
"in that order. ")
6768

69+
self.user = kwargs.get('user', self.CLIENT_DEFAULT_USER)
70+
self.app_name = kwargs.get('app_name', self.CLIENT_DEFAULT_APP_NAME)
6871
self.token = kwargs.get("token",
69-
kwargs.get("auth_token",
70-
kwargs.get("authToken", None)))
72+
kwargs.get(
73+
"auth_token",
74+
kwargs.get("authToken", None)))
7175

7276
self.jwt = kwargs.get("jwt", None)
7377

@@ -95,11 +99,25 @@ def __get_url_parts(self, url):
9599
Split the two parts of the api url
96100
:param url: Url of the api
97101
"""
98-
return self.__verify_url_complement(url.split("//")[-1]
99-
.split("/", maxsplit=1)
100-
if PY3
101-
else url.split("//")[-1]
102-
.split("/", 1))
102+
return self.__verify_url_complement(
103+
url.split("//")[-1].split("/", maxsplit=1) if PY3
104+
else url.split("//")[-1].split("/", 1))
105+
106+
def __generate_pragmas(self, comment=None):
107+
"""
108+
Generate pragmas to add to query
109+
:comment: Pragma comment free
110+
:user: Pragma comment user
111+
:app_name: Pragma comment id. App name.
112+
"""
113+
str_pragmas = ' pragma comment.id:"{}" ' \
114+
'pragma comment.user:"{}"'\
115+
.format(self.app_name, self.user)
116+
117+
if comment:
118+
return str_pragmas + ' pragma comment.free:"{}"'.format(comment)
119+
120+
return str_pragmas
103121

104122
def __verify_url_complement(self, url_list):
105123
"""
@@ -118,7 +136,7 @@ def from_config(config):
118136
return Client(**config)
119137

120138
@staticmethod
121-
def generate_dates(dates):
139+
def __generate_dates(dates):
122140
"""
123141
Generate and merge dates object
124142
:param dates: object with optios for query, see doc
@@ -149,36 +167,42 @@ def query(self, **kwargs):
149167

150168
query = kwargs.get('query', None)
151169
query_id = kwargs.get('query_id', None)
152-
dates = self.generate_dates(kwargs.get('dates', None))
170+
dates = self.__generate_dates(kwargs.get('dates', None))
153171
stream = kwargs.get('stream', True)
154172
processor = kwargs.get('processor', None)
173+
if query is not None:
174+
query += self.__generate_pragmas(comment=kwargs.get('comment', None))
155175

156176
opts = {'limit': kwargs.get('limit', None),
157177
'response': kwargs.get('response', self.response),
158178
'offset': kwargs.get('offset', None),
159-
'destination': kwargs.get('destination', None)}
179+
'destination': kwargs.get('destination', None)
180+
}
181+
182+
if not self.__stream_available(opts['response']) or not stream:
183+
if not dates['to']:
184+
dates['to'] = "now()"
160185

161-
if self.stream_available(opts['response']) or not stream:
162186
return self._call(
163187
self._get_payload(query, query_id, dates, opts),
164188
processor
165189
)
166-
else:
167-
if self.socket is None:
168-
self.connect()
169-
elif not self.status():
170-
self.connect()
171-
172-
if self.buffer is None:
173-
self.buffer = Buffer()
174-
self.buffer.create_thread(
175-
target=self._call_stream,
176-
kwargs=({'payload': self._get_payload(query, query_id,
177-
dates, opts)})
178-
)
179190

180-
self.buffer.start()
181-
return self.buffer
191+
if self.socket is None:
192+
self.connect()
193+
elif not self.status():
194+
self.connect()
195+
196+
if self.buffer is None:
197+
self.buffer = Buffer()
198+
self.buffer.create_thread(
199+
target=self._call_stream,
200+
kwargs=({'payload': self._get_payload(query, query_id,
201+
dates, opts)})
202+
)
203+
204+
self.buffer.start()
205+
return self.buffer
182206

183207
def status(self):
184208
"""
@@ -187,19 +211,21 @@ def status(self):
187211
timeit = int(round(time.time() * 1000)) - self.time_start
188212
if self.socket is None:
189213
return False
190-
elif self.timeout < timeit:
214+
215+
if self.timeout < timeit:
191216
self.close()
192217
return False
218+
193219
return True
194220

195221
@staticmethod
196-
def stream_available(resp):
222+
def __stream_available(resp):
197223
"""
198224
Verify if can stream resp from API by type of resp in opts
199225
:param resp: str
200226
:return: bool
201227
"""
202-
return resp == "json" or resp == "json/compact"
228+
return resp not in ["json", "json/compact"]
203229

204230
# API Call
205231
def _call(self, payload, processor):
@@ -212,11 +238,11 @@ def _call(self, payload, processor):
212238
tries = 0
213239
while tries < self.retries:
214240
try:
215-
response = requests.post("https://%s/%s" %
216-
(self.url, self.query_url),
217-
data=payload,
218-
headers=self._get_no_stream_headers(payload),
219-
verify=True, timeout=self.timeout)
241+
response = requests.post(
242+
"https://%s/%s" % (self.url, self.query_url),
243+
data=payload,
244+
headers=self._get_no_stream_headers(payload),
245+
verify=True, timeout=self.timeout)
220246
except ConnectionError as error:
221247
return {"status": 404, "error": error}
222248

@@ -225,13 +251,12 @@ def _call(self, payload, processor):
225251
"error" in response.text[0:15].lower():
226252
return {"status": response.status_code,
227253
"error": response.text}
228-
else:
229-
if processor is not None:
230-
return processor(response.text)
231-
return response.text
232-
else:
233-
tries += 1
234-
time.sleep(self.sleep)
254+
255+
if processor is not None:
256+
return processor(response.text)
257+
return response.text
258+
tries += 1
259+
time.sleep(self.sleep)
235260
return {}
236261

237262
def _call_stream(self, payload=None):
@@ -241,8 +266,10 @@ def _call_stream(self, payload=None):
241266
"""
242267
if self.socket is not None:
243268
self.socket.send(self._get_stream_headers(payload))
244-
if not self.buffer.close and not self.buffer.error and self.socket is not None:
245-
result, data = self.buffer.proccess_first_line(self.socket.recv(5000))
269+
if not self.buffer.close and not self.buffer.error\
270+
and self.socket is not None:
271+
result, data = self.buffer.proccess_first_line(
272+
self.socket.recv(5000))
246273
if result:
247274
try:
248275
while self.buffer.proccess_recv(self.socket.recv(5000)):
@@ -267,9 +294,8 @@ def _get_payload(query, query_id, dates, opts):
267294
:return: Return the formed payload
268295
"""
269296
payload = {"from": int(DateParser.default_from(dates['from']) / 1000),
270-
"to": int(DateParser.default_to(dates['to']) / 1000)
271-
if dates['to'] is not None else None,
272-
"query": query, "queryId": query_id,
297+
"to": int(DateParser.default_to(dates['to']) / 1000) if
298+
dates['to'] is not None else None,
273299
"mode": {"type": opts['response']}}
274300

275301
if query:
@@ -305,21 +331,23 @@ def _get_no_stream_headers(self, data):
305331
'x-logtrust-timestamp': tstamp,
306332
'x-logtrust-sign': sign
307333
}
308-
elif self.token:
334+
335+
if self.token:
309336
return {
310337
'Content-Type': 'application/json',
311338
'x-logtrust-timestamp': tstamp,
312339
'Authorization': "Bearer %s" % self.token
313340
}
314-
elif self.jwt:
341+
342+
if self.jwt:
315343
return {
316344
'Content-Type': 'application/json',
317345
'x-logtrust-timestamp': tstamp,
318346
'Authorization': "jwt %s" % self.jwt
319347
}
320348

321-
raise DevoClientException("Devo-Client|Client dont have key&secret or auth token/jwt")
322-
349+
raise DevoClientException("Devo-Client|Client dont have key&secret"
350+
" or auth token/jwt")
323351

324352
def _get_stream_headers(self, payload):
325353
"""
@@ -330,33 +358,34 @@ def _get_stream_headers(self, payload):
330358
tstamp = str(int(time.time()) * 1000)
331359

332360
headers = ("POST /%s HTTP/1.1\r\n"
333-
"Host: %s\r\n"
334-
"Content-Type: application/json\r\n"
335-
"Content-Length: %s \r\n"
336-
"Cache-Control: no-cache\r\n"
337-
"x-logtrust-timestamp: %s\r\n"
361+
"Host: %s\r\n"
362+
"Content-Type: application/json\r\n"
363+
"Content-Length: %s \r\n"
364+
"Cache-Control: no-cache\r\n"
365+
"x-logtrust-timestamp: %s\r\n"
338366
% (self.query_url, self.url, str(len(payload)), tstamp))
339367

340368
if self.key and self.secret:
341369
return ("%s"
342370
"x-logtrust-apikey: %s\r\n"
343371
"x-logtrust-sign: %s\r\n"
344372
"\r\n%s\r\n"
345-
% (headers, self.key, self._get_sign(payload, tstamp),
373+
% (headers, self.key, self._get_sign(payload, tstamp),
346374
payload)).encode("utf-8")
347-
elif self.token:
375+
if self.token:
348376
return ("%s"
349377
"Authorization: Bearer %s\r\n"
350378
"\r\n%s\r\n"
351379
% (headers, self.token, payload)).encode("utf-8")
352-
elif self.jwt:
380+
if self.jwt:
353381
return ("%s"
354382
"Authorization: jwt %s\r\n"
355383
"\r\n%s\r\n"
356384
% (headers, self.jwt, payload)).encode("utf-8")
357385

358386
self.buffer.error = "Client dont have key&secret or auth token/jwt"
359-
raise DevoClientException("Devo-Client|Client dont have key&secret or auth token/jwt")
387+
raise DevoClientException("Devo-Client|Client dont have key&secret"
388+
" or auth token/jwt")
360389

361390
def _get_sign(self, data, tstamp):
362391
"""
@@ -402,4 +431,3 @@ def close(self):
402431
if self.socket is not None:
403432
self.socket.close()
404433
self.socket = None
405-

0 commit comments

Comments
 (0)