From 69e272c6644f0804499e924d18b6fc54745ce859 Mon Sep 17 00:00:00 2001 From: Garrett Holmstrom Date: Thu, 25 Apr 2013 15:16:14 -0700 Subject: [PATCH] Add HTTP Get, a sample (but still somewhat useful) request --- bin/httpget | 6 +++ requestbuilder/commands/__init__.py | 13 +++++++ requestbuilder/commands/http.py | 57 +++++++++++++++++++++++++++++ setup.py | 6 ++- 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100755 bin/httpget create mode 100644 requestbuilder/commands/__init__.py create mode 100644 requestbuilder/commands/http.py diff --git a/bin/httpget b/bin/httpget new file mode 100755 index 0000000..839a188 --- /dev/null +++ b/bin/httpget @@ -0,0 +1,6 @@ +#!/usr/bin/python -tt + +import requestbuilder.commands.http + +if __name__ == '__main__': + requestbuilder.commands.http.Get.run() diff --git a/requestbuilder/commands/__init__.py b/requestbuilder/commands/__init__.py new file mode 100644 index 0000000..b89480d --- /dev/null +++ b/requestbuilder/commands/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Eucalyptus Systems, Inc. +# +# Permission to use, copy, modify, and/or distribute this software for +# any purpose with or without fee is hereby granted, provided that the +# above copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/requestbuilder/commands/http.py b/requestbuilder/commands/http.py new file mode 100644 index 0000000..b756cb2 --- /dev/null +++ b/requestbuilder/commands/http.py @@ -0,0 +1,57 @@ +# Copyright (c) 2013, Eucalyptus Systems, Inc. +# +# Permission to use, copy, modify, and/or distribute this software for +# any purpose with or without fee is hereby granted, provided that the +# above copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import argparse +import os.path +from requestbuilder import Arg, SERVICE +from requestbuilder.mixins import FileTransferProgressBarMixin +from requestbuilder.request import BaseRequest +import sys + + +class Get(BaseRequest, FileTransferProgressBarMixin): + DESCRIPTION = 'A simple HTTP GET request' + ARGS = [Arg('url', metavar='URL', route_to=SERVICE, + help='URL to download (required)'), + Arg('dest', metavar='PATH', route_to=None, + help='where to download to (required)'), + Arg('--label', route_to=None, help=argparse.SUPPRESS)] + + def parse_response(self, response): + if ('Content-Length' in response.headers and + response.headers.get('Content-Encoding') != 'gzip'): + # The Content-Length for a gzipped response is that of the + # compressed data, not the raw data that requests/urllib3 give us. + # Since we can't tell how much has been read from the socket from + # this level we don't show progress for gzipped # responses -- + # they'd overflow the max value otherwise. + maxval = int(response.headers['Content-Length']) + else: + maxval = None + label = self.args.get('label') or os.path.basename(self.args['url']) + bar = self.get_progressbar(label=label, maxval=maxval) + with open(self.get_dest_path(), 'w') as ofile: + bar.start() + for chunk in response.iter_content(chunk_size=8192): + ofile.write(chunk) + bar.update(ofile.tell()) + bar.finish() + return self.get_dest_path(), ofile.tell() + + def get_dest_path(self): + if os.path.isdir(self.args['dest']): + return os.path.join(self.args['dest'], + os.path.basename(self.args['url'])) + else: + return self.args['dest'] diff --git a/setup.py b/setup.py index 3afa458..650ebef 100644 --- a/setup.py +++ b/setup.py @@ -71,7 +71,9 @@ setup(name = 'requestbuilder', description = 'Command line-driven HTTP request builder', author = 'Garrett Holmstrom (gholms)', author_email = 'gholms@devzero.com', - packages = ['requestbuilder'], + packages = ['requestbuilder', + 'requestbuilder.commands', + ] license = 'ISC', platforms = 'Posix; MacOS X', classifiers = ['Development Status :: 3 - Alpha', @@ -83,8 +85,8 @@ setup(name = 'requestbuilder', 'Programming Language :: Python :: 2.7', 'Topic :: Internet'], install_requires = [ - "requests", "argparse", + "requests", "six", ], cmdclass = {'build_py': build_py_with_git_version,