forked from cloudant/python-cloudant
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchanges.py
More file actions
106 lines (88 loc) · 2.91 KB
/
Copy pathchanges.py
File metadata and controls
106 lines (88 loc) · 2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/env python
# Copyright (c) 2015 IBM. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
_feeds_
Iterator support for consuming changes-like feeds
"""
import json
class Feed(object):
"""
_Feed_
Acts as an infinite iterator for consuming database feeds such as
_changes, suitable for feeding a daemon.
:params:
"""
def __init__(self, session, url, include_docs=False, **kwargs):
self._session = session
self._url = url
self._resp = None
self._line_iter = None
self._last_seq = kwargs.get('since')
self._continuous = kwargs.get('continuous', False)
self._end_of_iteration = False
self._params = {'feed': 'continuous'}
if include_docs:
self._params['include_docs'] = 'true'
def start(self):
"""
_start_
Using the provided session, start streaming
the feed continuously,
if a last seq value is present, pass that along.
"""
params = self._params
if self._last_seq is not None:
params['since'] = self._last_seq
self._resp = self._session.get(self._url, params=params, stream=True)
self._resp.raise_for_status()
self._line_iter = self._resp.iter_lines()
def __iter__(self):
"""
make this object an iterator
"""
return self
def __next__(self):
"""python3 compat"""
return self.next()
def next(self):
"""
_next_
Iterate: pull next line out of the stream,
attempt to convert the response to JSON, handling
case of empty lines.
If end of feed is seen, restart iterator
Returns JSON data representing what was seen in the feed.
"""
if self._end_of_iteration:
raise StopIteration
if not self._resp:
self.start()
line = self._line_iter.next()
if len(line.strip()) == 0:
return {}
try:
data = json.loads(line)
except ValueError:
data = {"error": "Bad JSON line", "line": line}
if data.get('last_seq'):
if self._continuous:
# forever mode => restart
self._last_seq = data['last_seq']
self.start()
return {}
else:
# not forever mode => break
return data
return data