Merge lp:~noise/tanuki-agent/api_example into lp:tanuki-agent

Proposed by Bret Barker
Status: Merged
Approved by: Bret Barker
Approved revision: 82
Merged at revision: 79
Proposed branch: lp:~noise/tanuki-agent/api_example
Merge into: lp:tanuki-agent
Diff against target: 105 lines (+101/-0)
1 file modified
scripts/api_example.py (+101/-0)
To merge this branch: bzr merge lp:~noise/tanuki-agent/api_example
Reviewer Review Type Date Requested Status
Thomi Richards (community) Approve
Review via email: mp+269425@code.launchpad.net

Commit message

basic api_example.py to replace curl in docs for auth'd requests.

To post a comment you must log in.
lp:~noise/tanuki-agent/api_example updated
81. By Bret Barker

minor help text tweak

Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

This looks OK, but I really think we shouldn't be using docopt - it's not in the standard library, it's not as powerful as argparse, and we're supposed to be trying to avoid external dependencies.

Having said that, I clearly lost that argument already with the agent, and this will feed from the same virtualenv, so.. *shrugs*.

review: Approve
Revision history for this message
Bret Barker (noise) wrote :

Thomi - yeah, I wouldn't have used it if we were not already piggybacking on the agent's venv.

Revision history for this message
Facundo Batista (facundo) wrote :

Minor inline comments...

lp:~noise/tanuki-agent/api_example updated
82. By Bret Barker

add -v, -d alias for --data, more clear json err handling

Revision history for this message
Bret Barker (noise) wrote :

Facundo - thanks, added -d alias, tweaked try/except to be more narrow w/comment since it's just to handle "not json" response text.

Pedronis - added -v flag for debug output

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'scripts/api_example.py'
2--- scripts/api_example.py 1970-01-01 00:00:00 +0000
3+++ scripts/api_example.py 2015-08-27 21:06:07 +0000
4@@ -0,0 +1,101 @@
5+#!/usr/bin/env python3
6+"""
7+SPI Api_example - example wrapper for making oauth-signed calls to SPI API endpoints
8+
9+Usage:
10+ api_example.py [options] <configfile> <url>
11+
12+Options:
13+ -h --help Show this screen
14+ -d, --data data POST Data
15+ -X method HTTP Method
16+ -v Verbose debug output
17+"""
18+
19+import json
20+import logging
21+import sys
22+
23+from configparser import ConfigParser
24+import requests_oauthlib
25+
26+logging.basicConfig(format='%(asctime)s %(levelname)-5.5s %(name)s %(message)s')
27+logger = logging.getLogger(__name__)
28+
29+try:
30+ import docopt
31+except:
32+ print('This script must be run in the virtualenv, via:')
33+ print('. env/bin/activate')
34+ print('./scripts/api_example.py')
35+ sys.exit(0)
36+
37+
38+class ApiExample(object):
39+
40+ def __init__(self, arguments):
41+ self.config = ConfigParser()
42+ self.confpath = arguments['<configfile>']
43+ self.method = arguments.get('-X')
44+ self.url = arguments.get('<url>')
45+ pd = arguments.get('--data')
46+ self.post_data = json.loads(pd) if pd else None
47+
48+ if arguments.get('-v'):
49+ logger.setLevel(logging.DEBUG)
50+ requests_log = logging.getLogger("requests.packages.urllib3")
51+ requests_log.setLevel(logging.DEBUG)
52+ requests_log.propagate = True
53+ requests_oauthlib_log = logging.getLogger("requests_oauthlib")
54+ requests_oauthlib_log.setLevel(logging.DEBUG)
55+ else:
56+ logger.setLevel(logging.INFO)
57+
58+ # Load config
59+ if self.confpath is not None:
60+ self.config.read(self.confpath)
61+
62+ if 'auth' in self.config:
63+ # Here's the substance - we create a requests session
64+ # with our oauth credentials (read from config file)
65+ self.session = requests_oauthlib.OAuth1Session(
66+ self.config.get('auth', 'consumer_key'),
67+ client_secret=self.config.get('auth', 'consumer_secret'),
68+ resource_owner_key=self.config.get('auth', 'token_key'),
69+ resource_owner_secret=self.config.get('auth', 'token_secret'),
70+ )
71+ else:
72+ logger.warning("[auth] config section not found in %s", self.confpath)
73+ sys.exit(1)
74+
75+ def run(self):
76+ if self.method is None:
77+ if self.post_data is not None:
78+ self.method = 'POST'
79+ else:
80+ self.method = 'GET'
81+ logger.debug('%s %s', self.method, self.url)
82+ logger.debug('with data: %s', self.post_data)
83+
84+ if self.method == 'POST':
85+ res = self.session.post(self.url, json=self.post_data)
86+ elif self.method == 'PUT':
87+ res = self.session.put(self.url, json=self.post_data)
88+ elif self.method == 'DELETE':
89+ res = self.session.delete(self.url)
90+ else:
91+ res = self.session.get(self.url)
92+
93+ print('HTTP', res.status_code)
94+ try:
95+ print(json.dumps(res.json(), indent=2))
96+ except ValueError:
97+ # response is not json
98+ print(res.text)
99+ sys.exit(1)
100+
101+
102+if __name__ == '__main__':
103+ arguments = docopt.docopt(__doc__, version='SPI Api_example v1')
104+ api = ApiExample(arguments)
105+ api.run()

Subscribers

People subscribed via source and target branches

to all changes: