Skip to content

Commit 381e60a

Browse files
committed
Full support to Result dynamic and lazy iterator
It paginate the requests that needs and does the real requests in the final moment
1 parent 78622f0 commit 381e60a

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed

pygithub3/core/result.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
4+
from urlparse import urlparse, parse_qs
5+
6+
from .third_libs.link_header import parse_link_value
7+
8+
9+
class Method(object):
10+
11+
def __init__(self, method, resource, **method_args):
12+
self.method = method
13+
self.resource = resource
14+
self.args = method_args
15+
self.cache = {}
16+
17+
def cached(func):
18+
def wrapper(self, page=1):
19+
if self.cache.has_key(str(page)):
20+
return self.cache[str(page)]
21+
return func(self, page)
22+
return wrapper
23+
24+
def if_needs_lastpage(func):
25+
def wrapper(self, response):
26+
#import ipdb; ipdb.set_trace()
27+
has_link = response.headers.get('link')
28+
has_last_page = hasattr(self, 'last_page')
29+
if not has_last_page and has_link:
30+
return func(self, response)
31+
elif not has_last_page and not has_link:
32+
self.last_page = 1
33+
return wrapper
34+
35+
@if_needs_lastpage
36+
def __set_last_page_from(self, response):
37+
#import ipdb; ipdb.set_trace()
38+
link_parsed = parse_link_value(response.headers['link'])
39+
def get_last(url):
40+
url_rels = link_parsed[url]
41+
return (url_rels.get('rel') == 'last')
42+
url_last = filter(get_last, link_parsed)
43+
query = urlparse(url_last.pop()).query
44+
self.last_page = int(parse_qs(query).get('page').pop())
45+
46+
@cached
47+
def __call__(self, page=1):
48+
all_args = self.args.copy()
49+
all_args.update(page=page)
50+
response = self.method(self.resource, **all_args)
51+
self.__set_last_page_from(response)
52+
model = self.resource.get_model()
53+
self.cache[str(page)] = model.loads(response.content)
54+
return self.cache[str(page)]
55+
56+
@property
57+
def last(self):
58+
if not hasattr(self, 'last_page'):
59+
self()
60+
return self.last_page
61+
62+
class Page(object):
63+
""" """
64+
65+
def __init__(self, getter, page=1):
66+
""" """
67+
self.getter = getter
68+
self.page = page
69+
70+
def __iter__(self):
71+
return self
72+
73+
def __add__(self, number):
74+
return self.page + number
75+
76+
def __radd__(self, number):
77+
return number + self.page
78+
79+
def __sub__(self, number):
80+
return self.page - number
81+
82+
def __rsub__(self, number):
83+
return number - self.page
84+
85+
def __lt__(self, number):
86+
return self.page < number
87+
88+
def __le__(self, number):
89+
return self.page <= number
90+
91+
def __eq__(self, number):
92+
return self.page == number
93+
94+
def __ne__(self, number):
95+
return self.page != number
96+
97+
def __gt__(self, number):
98+
return self.page > number
99+
100+
def __ge__(self, number):
101+
return self.page >= number
102+
103+
@property
104+
def resources(self):
105+
return getattr(self, '_count', None) or u"~"
106+
107+
def get_content(func):
108+
def wrapper(self):
109+
if not hasattr(self, '_count'):
110+
content = self.getter(self.page)
111+
self._count = len(content)
112+
self.iterable = iter(content)
113+
return func(self)
114+
return wrapper
115+
116+
@get_content
117+
def __next__(self):
118+
try:
119+
return self.iterable.next()
120+
except StopIteration:
121+
self.iterable = iter(self.getter(self.page))
122+
raise StopIteration
123+
124+
def next(self):
125+
return self.__next__()
126+
127+
def __str__(self):
128+
return '<{name}{page} resources={resources}>'.format(
129+
name=self.__class__.__name__,
130+
page=self.page,
131+
resources=self.resources)
132+
133+
def __repr__(self):
134+
return "%s[%d]" % (self.__str__(), id(self))
135+
136+
137+
class Result(object):
138+
""" """
139+
140+
def __init__(self, client, resource, **kwargs):
141+
""" """
142+
self.getter = Method(client.get, resource, **kwargs)
143+
self.page = Page(self.getter)
144+
145+
def __iter__(self):
146+
return self
147+
148+
def __next__(self):
149+
if self.page <= self.pages:
150+
page_to_return = self.page
151+
self.page = Page(self.getter, page_to_return + 1)
152+
return page_to_return
153+
self.page = Page(self.getter)
154+
raise StopIteration
155+
156+
def next(self):
157+
return self.__next__()
158+
159+
@property
160+
def pages(self):
161+
return self.getter.last
162+
163+
def get_page(self, page):
164+
if page in xrange(1, self.pages + 1):
165+
return Page(self.getter, page)
166+
return None
167+
168+
def all(self):
169+
for page in self:
170+
for resource in page:
171+
yield resource

0 commit comments

Comments
 (0)