123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- #!/usr/bin/env python
- # encoding: utf-8
- import sys
- import requests
- from Naked.settings import debug as DEBUG_FLAG
- #------------------------------------------------------------------------------
- #[ HTTP class]
- # handle HTTP requests
- # Uses the requests external library to handle HTTP requests and response object (available on PyPI)
- #------------------------------------------------------------------------------
- class HTTP():
- def __init__(self, url="", request_timeout=10):
- self.url = url
- self.request_timeout = request_timeout
- #------------------------------------------------------------------------------
- # HTTP response properties (assignment occurs with the HTTP request methods)
- #------------------------------------------------------------------------------
- self.res = None # assigned with the requests external library response object after a HTTP method call
- #------------------------------------------------------------------------------
- # [ get method ] (string) -
- # HTTP GET request - returns text string
- # returns data stream read from the URL (string)
- # Default timeout = 10 s from class constructor
- # Re-throws ConnectionError on failed connection (e.g. no site at URL)
- # Test : test_NETWORK.py :: test_http_get, test_http_get_response_change,
- # test_http_post_reponse_change, test_http_get_response_check
- #------------------------------------------------------------------------------
- def get(self, follow_redirects=True):
- try:
- response = requests.get(self.url, timeout=self.request_timeout, allow_redirects=follow_redirects)
- self.res = response # assign the response object from requests to a property on the instance of HTTP class
- return response.text
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to perform GET request with the URL " + self.url + " using the get() method (Naked.toolshed.network.py)")
- raise e
- #------------------------------------------------------------------------------
- # [ get_data method ] (binary data)
- # HTTP GET request, return binary data
- # returns data stream with raw binary data
- #------------------------------------------------------------------------------
- def get_bin(self):
- try:
- response = requests.get(self.url, timeout=self.request_timeout)
- self.res = response # assign the response object from requests to a property on the instance
- return response.content # return binary data instead of text (get() returns text)
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to perform GET request with the URL " + self.url + " using the get_data() method (Naked.toolshed.network.py)")
- raise e
- #------------------------------------------------------------------------------
- # [ get_bin_write_file method ] (boolean)
- # open HTTP data stream with GET request, make file with the returned binary data
- # file path is passed to the method by the developer
- # set suppress_output to True if you want to suppress the d/l status information that is printed to the standard output stream
- # return True on successful pull and write to disk
- # Tests: test_NETWORK.py :: test_http_get_binary
- #------------------------------------------------------------------------------
- def get_bin_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
- try:
- import os # used for os.fsync() method in the write
- # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
- if not overwrite_existing:
- from Naked.toolshed.system import file_exists
- if file_exists(filepath):
- if not suppress_output:
- print("Download aborted. A local file with the requested filename exists on the path.")
- return False
- if (filepath == "" and len(self.url) > 1):
- filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
- if not suppress_output:
- sys.stdout.write("Downloading file from " + self.url + "...")
- sys.stdout.flush()
- response = requests.get(self.url, timeout=self.request_timeout, stream=True)
- self.res = response
- with open(filepath, 'wb') as f: # write as binary data
- for chunk in response.iter_content(chunk_size=2048):
- f.write(chunk)
- f.flush()
- os.fsync(f.fileno()) # flush all internal buffers to disk
- if not suppress_output:
- print(" ")
- print("Download complete.")
- return True # return True if successful write
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to perform GET request and write file with the URL " + self.url + " using the get_bin_write_file() method (Naked.toolshed.network.py)")
- raise e
- #------------------------------------------------------------------------------
- # [ get_txt_write_file method ] (boolean)
- # open HTTP data stream with GET request, write file with utf-8 encoded text using returned text data
- # file path is passed to the method by the developer (default is the base filename in the URL if not specified)
- # return True on successful pull and write to disk
- # Tests: test_NETWORK.py :: test_http_get_text
- #------------------------------------------------------------------------------
- def get_txt_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
- try:
- import os # used for os.fsync() method in the write
- # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
- if not overwrite_existing:
- from Naked.toolshed.system import file_exists
- if file_exists(filepath):
- if not suppress_output:
- print("Download aborted. A local file with the requested filename exists on the path.")
- return False
- if (filepath == "" and len(self.url) > 1):
- filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
- if not suppress_output:
- sys.stdout.write("Downloading file from " + self.url + "...")
- sys.stdout.flush()
- response = requests.get(self.url, timeout=self.request_timeout, stream=True)
- self.res = response
- import codecs
- with codecs.open(filepath, mode='w', encoding="utf-8") as f: #write as text
- for chunk in response.iter_content(chunk_size=2048):
- chunk = chunk.decode('utf-8')
- f.write(chunk)
- f.flush()
- os.fsync(f.fileno()) # flush all internal buffers to disk
- if not suppress_output:
- print(" ")
- print("Download complete.")
- return True # return True if successful write
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to perform GET request and write file with the URL " + self.url + " using the get_data_write_txt() method (Naked.toolshed.network.py)")
- raise e
- #------------------------------------------------------------------------------
- # [ head method ] (dictionary of strings)
- # HTTP HEAD request
- # returns a dictionary of the header strings
- # test for a specific header on either the response dictionary or the instance res property
- # Usage example:
- # content_type = instance.res['content-type']
- # Tests: test_NETWORK.py :: test_http_head
- #------------------------------------------------------------------------------
- def head(self):
- try:
- response = requests.head(self.url, timeout=self.request_timeout)
- self.res = response # assign the response object from requests to a property on the instance of HTTP class
- return response.headers
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to perform a HEAD request with the head() method (Naked.toolshed.network.py).")
- raise e
- #------------------------------------------------------------------------------
- # [ post method ] (string)
- # HTTP POST request for text
- # returns text from the URL as a string
- #------------------------------------------------------------------------------
- def post(self, follow_redirects=True):
- try:
- response = requests.post(self.url, timeout=self.request_timeout, allow_redirects=follow_redirects)
- self.res = response # assign the response object from requests to a property on the instance of HTTP class
- return response.text
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.exit("Naked Framework Error: Unable to perform a POST request with the post() method (Naked.toolshed.network.py).")
- raise e
- #------------------------------------------------------------------------------
- # [ post_bin method ] (binary data)
- # HTTP POST request for binary data
- # returns binary data from the URL
- #------------------------------------------------------------------------------
- def post_bin(self):
- try:
- response = requests.post(self.url, timeout=self.request_timeout)
- self.res = response # assign the response object from requests to a property on the instance of HTTP class
- return response.content
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.exit("Naked Framework Error: Unable to perform POST request with the post_bin() method (Naked.toolshed.network.py).")
- raise e
- #------------------------------------------------------------------------------
- # [ post_bin_write_file method ] (boolean = success of write)
- # HTTP POST request, write binary file with the response data
- # default filepath is the basename of the URL file, may be set by passing an argument to the method
- # returns a boolean that indicates the success of the file write
- #------------------------------------------------------------------------------
- def post_bin_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
- try:
- import os # used for os.fsync() method in the write
- # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
- if not overwrite_existing:
- from Naked.toolshed.system import file_exists
- if file_exists(filepath):
- if not suppress_output:
- print("Download aborted. A local file with the requested filename exists on the path.")
- return False
- if (filepath == "" and len(self.url) > 1):
- filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
- if not suppress_output:
- sys.stdout.write("Downloading file from " + self.url + "...") #provide information about the download to user
- sys.stdout.flush()
- response = requests.post(self.url, timeout=self.request_timeout, stream=True)
- self.res = response
- with open(filepath, 'wb') as f: # write as binary data
- for chunk in response.iter_content(chunk_size=2048):
- f.write(chunk)
- f.flush()
- os.fsync(f.fileno()) # flush all internal buffers to disk
- if not suppress_output:
- print(" ")
- print("Download complete.") # provide user with completion information
- return True # return True if successful write
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to perform POST request and write file with the URL " + self.url + " using the post_data_write_bin() method (Naked.toolshed.network.py)")
- raise e
- #------------------------------------------------------------------------------
- # [ post_txt_write_file method ] (boolean = success of file write)
- # HTTP POST request, write utf-8 encoded text file with the response data
- # default filepath is the basename of the URL file, may be set by passing an argument to the method
- # returns a boolean that indicates the success of the file write
- #------------------------------------------------------------------------------
- def post_txt_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
- try:
- import os # used for os.fsync() method in the write
- # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
- if not overwrite_existing:
- from Naked.toolshed.system import file_exists
- if file_exists(filepath):
- if not suppress_output:
- print("Download aborted. A local file with the requested filename exists on the path.")
- return False
- if (filepath == "" and len(self.url) > 1):
- filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
- if not suppress_output:
- sys.stdout.write("Downloading file from " + self.url + "...") #provide information about the download to user
- sys.stdout.flush()
- response = requests.post(self.url, timeout=self.request_timeout, stream=True)
- self.res = response
- import codecs
- with codecs.open(filepath, mode='w', encoding="utf-8") as f: # write as binary data
- for chunk in response.iter_content(chunk_size=2048):
- chunk = chunk.decode('utf-8')
- f.write(chunk)
- f.flush()
- os.fsync(f.fileno()) # flush all internal buffers to disk
- if not suppress_output:
- print(" ")
- print("Download complete.") # provide user with completion information
- return True # return True if successful write
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to perform POST request and write file with the URL " + self.url + " using the post_data_write_bin() method (Naked.toolshed.network.py)")
- raise e
- #------------------------------------------------------------------------------
- # [ response method ]
- # getter method for the requests library object that is assigned as a property
- # on the HTTP class after a HTTP request method is run (e.g. get())
- # Note: must run one of the HTTP request verbs to assign this property before use of getter (=None by default)
- # Tests: test_NETWORK.py :: test_http_get_response_check
- #------------------------------------------------------------------------------
- def response(self):
- try:
- return self.res
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to return the response from your HTTP request with the response() method (Naked.toolshed.network.py).")
- raise e
- #------------------------------------------------------------------------------
- # [ get_status_ok method ] (boolean)
- # return boolean whether HTTP response was in 200 status code range for GET request
- # Note: this method runs its own GET request, does not need to be run separately
- # Tests: test_NETWORK.py ::
- #------------------------------------------------------------------------------
- def get_status_ok(self):
- try:
- self.get() #run the get request
- if self.res and self.res.status_code:
- return (self.res.status_code == requests.codes.ok)
- else:
- return False
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to obtain the HTTP status with the get_status_ok() method (Naked.toolshed.network.py).")
- raise e
- #------------------------------------------------------------------------------
- # [ post_status_ok method ] (boolean)
- # return boolean whether HTTP response was in 200 status code range for POST request
- # Note: method runs its own post method, not necessary to run separately
- #------------------------------------------------------------------------------
- def post_status_ok(self):
- try:
- self.post() #run the post request
- if self.res and self.res.status_code:
- return (self.res.status_code == requests.codes.ok)
- else:
- return False
- except requests.exceptions.ConnectionError as ce:
- return False
- except Exception as e:
- if DEBUG_FLAG:
- sys.stderr.write("Naked Framework Error: Unable to obtain the HTTP status with the post_status_ok() method (Naked.toolshed.network.py).")
- raise e
- if __name__ == '__main__':
- pass
- #------------------------------------------------------------------------------
- # HTTP GET 1
- #------------------------------------------------------------------------------
- # http = HTTP("http://www.google.com")
- # data = http.get()
- # print(data)
- # from Naked.toolshed.file import FileWriter
- # w = FileWriter("testfile.txt")
- # w.write_utf8(data)
- #------------------------------------------------------------------------------
- # HTTP GET 2
- #------------------------------------------------------------------------------
- # http = HTTP()
- # http.url = "http://www.google.com"
- # print(http.get())
|