Skip to content
Merged

V1 #100

Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
a9cb909
add insecure ssl option
ischneider Jan 26, 2017
30739f0
very basic data api filter assembly functions
ischneider Feb 5, 2017
d188588
add lenient ISO date parsing and test
ischneider Feb 5, 2017
0e5755d
v1 data api client, dispatch and body changes
ischneider Feb 5, 2017
f2482dc
v1 initial data CLI - stats, search, searches
ischneider Feb 5, 2017
b6ee1d2
allow optional page_size in quick_search
ischneider Feb 8, 2017
b3e7c7e
add assets, activate, download to client
ischneider Feb 8, 2017
e62a08c
check status ok on all 2xx http status
ischneider Feb 8, 2017
ef430cd
get_filename returns whatever is in header
ischneider Feb 8, 2017
9207dd5
fix string/num in filter building
ischneider Feb 8, 2017
8db6f0c
add filter-json option, DRY up handling
ischneider Feb 8, 2017
e0307cd
initial activate/download - dirty/working
ischneider Feb 8, 2017
0b1c01b
search request + filter handling changes
ischneider Feb 9, 2017
560fc82
use new downloader
ischneider Feb 9, 2017
38b8d2d
option reformatting/cleanup
ischneider Feb 9, 2017
aa997ed
cli docgen updates + lint fixes
ischneider Feb 13, 2017
3be75d4
unpeg dep versions, move to requirements
ischneider Feb 13, 2017
774d150
do battle with pex incantations + dep versions
ischneider Feb 13, 2017
68f2b76
dispatcher use separate sync/async, throttling
ischneider Feb 13, 2017
ffe88cc
make download stages start explicitly
ischneider Feb 13, 2017
79cb697
more shutdown handling
ischneider Feb 13, 2017
71eef57
add retry on OverQuota, some DRY-up
ischneider Feb 14, 2017
6ba90ee
make Body write callback args more explicit
ischneider Feb 14, 2017
cf61856
activate/download rudimentary tests, other
ischneider Feb 14, 2017
f1ec1cf
use limit size if lt page size, stats output
ischneider Feb 14, 2017
d14837f
logging adjustments
ischneider Feb 14, 2017
20a97f5
bump version to 1.0.0dev1
ischneider Feb 14, 2017
ab7ab02
sort order support in client
ischneider Feb 14, 2017
0ccb969
fix breakage introduced with 68f2b76
ischneider Feb 14, 2017
1eb6766
sniffing for incoming item_types should not die
ischneider Feb 14, 2017
2d904c2
add current v1 CLI examples
ischneider Feb 14, 2017
7414bce
stage exits on unepected error
ischneider Feb 23, 2017
9c1a53d
more lenient date parsing
ischneider Feb 23, 2017
b7e0a3b
stats monitor exits when file closed
ischneider Feb 23, 2017
1fcd5d8
speedup helpers test + py3 compat
ischneider Feb 23, 2017
796c234
break apart scripts module into parts
ischneider Feb 23, 2017
81fa525
break apart v0/v1/general cli tests
ischneider Feb 23, 2017
7c2b024
sphinx cli doc generation updates
ischneider Feb 23, 2017
de845cf
remove v0 cli examples from doc
ischneider Feb 23, 2017
00f2aea
add glob + optional prefix match to choice
ischneider Feb 23, 2017
04cd90b
add sort order option, renamed request_opts
ischneider Feb 23, 2017
4c8f2f9
fix default flag val for get_searches
ischneider Feb 23, 2017
5ae56cc
add dry-run option and saved search to download
ischneider Feb 23, 2017
dfd100d
add search help epilog detailing formats
ischneider Feb 23, 2017
3ec83d2
update generated cli reference
ischneider Feb 23, 2017
f64d580
sphinx theme updates/tweaks
ischneider Feb 23, 2017
4dce99a
remove print stmt, replace w/ mock assert
ischneider Feb 24, 2017
72c2e33
api doc updates
ischneider Feb 24, 2017
cd6dc4d
remove v0 remnants
ischneider Feb 26, 2017
806df72
differentiate between throttle and quota
ischneider Feb 26, 2017
01f7ae5
add mini-check for --filter-json option
ischneider Feb 26, 2017
5fb4d00
rename funcs for clarity, more docs
ischneider Feb 26, 2017
fa503be
search filter doctests
ischneider Feb 26, 2017
4768a34
fix tests after v0 removal, more coverage
ischneider Feb 26, 2017
477fbb5
clarify model names, add Searches body, docs
ischneider Feb 26, 2017
deb9973
slightly better check for geometry_from_json
ischneider Feb 26, 2017
c9e098b
testing - add more asserts, traceback when fail
ischneider Feb 26, 2017
e6c7ee6
prevent error in python3 if limit is None
ischneider Feb 26, 2017
4f45501
small doc tweaks, fix example
ischneider Feb 26, 2017
feb0978
build: add coverage, auto-docs targets, enable doctests
ischneider Feb 26, 2017
9bc266f
downloader output final, correcter stats
ischneider Feb 27, 2017
07e6625
fix pex build after main rename
ischneider Feb 27, 2017
e974c54
numerous downloader fixes/bettering
ischneider Feb 27, 2017
ae7ac58
fix login and client URLs
ischneider Feb 28, 2017
a1517ac
download fails fast when dest dir unwritable
ischneider Feb 28, 2017
c96e903
handle any search api errors in download
ischneider Feb 28, 2017
69f80c8
cli regrouping
ischneider Mar 1, 2017
8345d1d
remove some words from geom_filter help
ischneider Mar 1, 2017
51defe0
docs - toc depth, fixed sidebar
ischneider Mar 1, 2017
c96a521
fix tests broken by cli regroup
ischneider Mar 2, 2017
f1b1b50
add overwrite option to write_to_file
ischneider Mar 2, 2017
38dbb97
Body.name is property, add doc
ischneider Mar 2, 2017
a44491c
sphinx - disable view extension
ischneider Mar 2, 2017
e45c5d1
add TooManyRequests to api namespace
ischneider Mar 2, 2017
d26fb0b
minor log level refinements
ischneider Mar 2, 2017
428f8b6
client funcs, cleanup, and more docs + tests
ischneider Mar 2, 2017
20fb492
download not handling sort option properly
ischneider Mar 2, 2017
ec64a35
minor lint
ischneider Mar 7, 2017
9a79da7
allow item-type, asset-type options with csv
ischneider Mar 7, 2017
8ab3193
replace sphinx markup in metavar cli output
ischneider Mar 7, 2017
7382caa
api fix - adjust argument handling to expected type
ischneider Mar 7, 2017
6e06431
remove duplicate sort_order option
ischneider Mar 7, 2017
ddab736
fix saved-search handling in download cmd
ischneider Mar 7, 2017
a0dc478
minor lint + doc fixes
ischneider Mar 7, 2017
5dc128d
client - patch in valid stats filter
ischneider Mar 7, 2017
9fcb7f6
add permission filter for stats, search, download
ischneider Mar 7, 2017
cf5c161
activate returns incorrect body type
ischneider Mar 7, 2017
dd9fcbd
only parse last-modified when present
ischneider Mar 7, 2017
178313f
add newline after JSON output if pretty
ischneider Mar 3, 2017
77d6499
downloader - add activate only, cleaner, better
ischneider Mar 3, 2017
9713f96
dispatch - throttle all session.request calls
ischneider Mar 9, 2017
7db005e
range filter values must be number
ischneider Mar 9, 2017
1486f61
Update README
ischneider Mar 10, 2017
341e9f7
refactor downloader output, don't swallow apikey err
ischneider Mar 27, 2017
1e1bf4c
fix broken cancellation in download stage
ischneider Mar 27, 2017
0835eed
add a scripts module __main__
ischneider Mar 27, 2017
1ef5c33
use click.Path options for downloader dest
ischneider Mar 27, 2017
ed282d1
I missed my self
ischneider Mar 27, 2017
8d76957
enabled some download logging on win
ischneider Mar 27, 2017
c596a37
python3 goofup begone
ischneider Mar 27, 2017
a11a19f
skip dest write check if only activating
ischneider Mar 28, 2017
68acb0a
docs - remove api instability warning
ischneider Mar 31, 2017
c0c4d58
remove random commented stmt
ischneider Mar 31, 2017
36afbae
add filters module to api package
ischneider Mar 31, 2017
5b9bffd
docs - planet labs -> planet api
ischneider Mar 31, 2017
a892c14
docs/examples - updates, remove old, minor css
ischneider Mar 31, 2017
e5e3af4
move __version__ to api package
ischneider Apr 1, 2017
3dc9894
make travis happier, do more stuff
ischneider Apr 1, 2017
b0a0a34
cli reference doc update
ischneider Apr 1, 2017
1de274e
minor doc gen fixes
ischneider Apr 1, 2017
a6b24a3
release version 1.0.0
ischneider Apr 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
dispatcher use separate sync/async, throttling
- use separate futures session to avoid blocking shorter
  api calls when async pool is exhausted
- add global throttle to avoid rate limits
- some DRY on header handling, comments + logging
- adjust former async handling of responses where needed
  e.g. remove resp.result()
  • Loading branch information
ischneider committed Feb 14, 2017
commit 68f2b76573d9def18fd85006bb2dcfa28b87376b
2 changes: 1 addition & 1 deletion planet/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def login(self, identity, credentials):
result = self.dispatcher.session.post(self._url('auth/login'), {
'email': identity,
'password': credentials
}).result()
})
status = result.status_code
if status == 400:
raise APIException('invalid parameters, login process has changed')
Expand Down
97 changes: 73 additions & 24 deletions planet/api/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os
import re
import threading
import time
from requests_futures.sessions import FuturesSession
from requests import Request
from requests import Session
from . utils import check_status
from . models import Response
from . exceptions import InvalidAPIKey
Expand All @@ -24,14 +28,41 @@

USE_STRICT_SSL = not (os.getenv('DISABLE_STRICT_SSL', '').lower() == 'true')

log = logging.getLogger(__name__)


def _log_request(req):
log.info('%s %s %s %s', req.method, req.url, req.params, req.data)


def _is_subdomain_of_tld(url1, url2):
orig_host = urlparse(url1).hostname
re_host = urlparse(url2).hostname
return orig_host.split('.')[-2:] == re_host.split('.')[-2:]


class RedirectSession(FuturesSession):
class _Throttler(object):
'''A context manager that allows at most ops/sec
to avoid request throttling for all client operations.
'''

def __init__(self, ops=4):
self._cond = threading.Semaphore()
self._wait = 1./ops

def __enter__(self):
self._cond.acquire()
self._t = time.time()

def __exit__(self, *exc):
w = self._wait - (time.time() - self._t)
if w > 0:
time.sleep(w)
self._cond.release()
return False


class RedirectSession(Session):
'''This exists to override the existing behavior of requests that will
strip Authorization headers from any redirect requests that resolve to a
new domain. Instead, we'll keep headers if the redirect is a subdomain
Expand All @@ -54,39 +85,56 @@ def rebuild_auth(self, prepared_request, response):
)


def _headers(request):
headers = {}
if request.data:
headers['Content-Type'] = 'application/json'
if request.auth:
headers.update({
'Authorization': 'api-key %s' % request.auth.value
})
else:
raise InvalidAPIKey('No API key provided')
return headers


class RequestsDispatcher(object):

def __init__(self, workers=4):
self.session = RedirectSession(max_workers=workers)
# general session for sync api calls
self.session = RedirectSession()
# the asyncpool is reserved for long-running async tasks
self._asyncpool = FuturesSession(
max_workers=workers,
session=self.session)
self._throttler = _Throttler()

def response(self, request):
return Response(request, self)

def _dispatch_async(self, request, callback):
auth = request.auth
if not auth:
raise InvalidAPIKey('No API key provided')

def _auth_callback(req):
req.headers.update({
'Authorization': 'api-key %s' % auth.value
})
return req

headers = {}
if request.data:
headers['Content-Type'] = 'application/json'
return self.session.request(
request.method, request.url, data=request.data, headers=headers,
params=request.params, stream=True, background_callback=callback,
auth=_auth_callback, verify=USE_STRICT_SSL
)
with self._throttler:
_log_request(request)
return self._asyncpool.request(
request.method, request.url, data=request.data,
headers=_headers(request), params=request.params, stream=True,
background_callback=callback, verify=USE_STRICT_SSL
)

def _dispatch(self, request, callback=None):
response = self._dispatch_async(request, callback).result()
check_status(response)
return response

with self._throttler:
_log_request(request)
t = time.time()
response = self.session.request(
request.method, request.url, data=request.data,
headers=_headers(request), params=request.params, stream=True,
verify=USE_STRICT_SSL
)
check_status(response)
log.info('request took %.03f', time.time() - t)
return response

# @todo delete me w/ v0 removal
def dispatch_request(self, method, url, auth=None, params=None, data=None):
headers = {}
content_type = 'application/json'
Expand All @@ -96,4 +144,5 @@ def dispatch_request(self, method, url, auth=None, params=None, data=None):
'Content-Type': content_type
})
req = Request(method, url, params=params, data=data, headers=headers)
_log_request(req)
return self.session.send(req.prepare(), verify=USE_STRICT_SSL)
6 changes: 3 additions & 3 deletions tests/test_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ def test_redirectsession_rebuilt_auth_called():
m.get('http://newredirect.com', text='redirected!')

# base assertion, works as intended
resp = session.get('http://redirect.com').result()
resp = session.get('http://redirect.com')
assert resp.url == 'http://newredirect.com'
assert resp.text == 'redirected!'

# Authorization headers unpacked and URL is rewritten
resp = session.get('http://redirect.com', headers={
'Authorization': 'api-key foobar'
}).result()
})
assert resp.url == 'http://newredirect.com/?api_key=foobar'
assert resp.text == 'redirected!'

Expand All @@ -44,7 +44,7 @@ def test_redirectsession_rebuilt_auth_called():
m.get('http://newredirect.com?param=yep', text='param!')
resp = session.get('http://redirect.com?param=yep', headers={
'Authorization': 'api-key foobar'
}).result()
})
assert resp.url == 'http://newredirect.com/?param=yep&api_key=foobar'
assert resp.text == 'param!'

Expand Down