network.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. import sys
  4. import requests
  5. from Naked.settings import debug as DEBUG_FLAG
  6. #------------------------------------------------------------------------------
  7. #[ HTTP class]
  8. # handle HTTP requests
  9. # Uses the requests external library to handle HTTP requests and response object (available on PyPI)
  10. #------------------------------------------------------------------------------
  11. class HTTP():
  12. def __init__(self, url="", request_timeout=10):
  13. self.url = url
  14. self.request_timeout = request_timeout
  15. #------------------------------------------------------------------------------
  16. # HTTP response properties (assignment occurs with the HTTP request methods)
  17. #------------------------------------------------------------------------------
  18. self.res = None # assigned with the requests external library response object after a HTTP method call
  19. #------------------------------------------------------------------------------
  20. # [ get method ] (string) -
  21. # HTTP GET request - returns text string
  22. # returns data stream read from the URL (string)
  23. # Default timeout = 10 s from class constructor
  24. # Re-throws ConnectionError on failed connection (e.g. no site at URL)
  25. # Test : test_NETWORK.py :: test_http_get, test_http_get_response_change,
  26. # test_http_post_reponse_change, test_http_get_response_check
  27. #------------------------------------------------------------------------------
  28. def get(self, follow_redirects=True):
  29. try:
  30. response = requests.get(self.url, timeout=self.request_timeout, allow_redirects=follow_redirects)
  31. self.res = response # assign the response object from requests to a property on the instance of HTTP class
  32. return response.text
  33. except requests.exceptions.ConnectionError as ce:
  34. return False
  35. except Exception as e:
  36. if DEBUG_FLAG:
  37. sys.stderr.write("Naked Framework Error: Unable to perform GET request with the URL " + self.url + " using the get() method (Naked.toolshed.network.py)")
  38. raise e
  39. #------------------------------------------------------------------------------
  40. # [ get_data method ] (binary data)
  41. # HTTP GET request, return binary data
  42. # returns data stream with raw binary data
  43. #------------------------------------------------------------------------------
  44. def get_bin(self):
  45. try:
  46. response = requests.get(self.url, timeout=self.request_timeout)
  47. self.res = response # assign the response object from requests to a property on the instance
  48. return response.content # return binary data instead of text (get() returns text)
  49. except requests.exceptions.ConnectionError as ce:
  50. return False
  51. except Exception as e:
  52. if DEBUG_FLAG:
  53. 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)")
  54. raise e
  55. #------------------------------------------------------------------------------
  56. # [ get_bin_write_file method ] (boolean)
  57. # open HTTP data stream with GET request, make file with the returned binary data
  58. # file path is passed to the method by the developer
  59. # set suppress_output to True if you want to suppress the d/l status information that is printed to the standard output stream
  60. # return True on successful pull and write to disk
  61. # Tests: test_NETWORK.py :: test_http_get_binary
  62. #------------------------------------------------------------------------------
  63. def get_bin_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
  64. try:
  65. import os # used for os.fsync() method in the write
  66. # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
  67. if not overwrite_existing:
  68. from Naked.toolshed.system import file_exists
  69. if file_exists(filepath):
  70. if not suppress_output:
  71. print("Download aborted. A local file with the requested filename exists on the path.")
  72. return False
  73. if (filepath == "" and len(self.url) > 1):
  74. filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
  75. if not suppress_output:
  76. sys.stdout.write("Downloading file from " + self.url + "...")
  77. sys.stdout.flush()
  78. response = requests.get(self.url, timeout=self.request_timeout, stream=True)
  79. self.res = response
  80. with open(filepath, 'wb') as f: # write as binary data
  81. for chunk in response.iter_content(chunk_size=2048):
  82. f.write(chunk)
  83. f.flush()
  84. os.fsync(f.fileno()) # flush all internal buffers to disk
  85. if not suppress_output:
  86. print(" ")
  87. print("Download complete.")
  88. return True # return True if successful write
  89. except requests.exceptions.ConnectionError as ce:
  90. return False
  91. except Exception as e:
  92. if DEBUG_FLAG:
  93. 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)")
  94. raise e
  95. #------------------------------------------------------------------------------
  96. # [ get_txt_write_file method ] (boolean)
  97. # open HTTP data stream with GET request, write file with utf-8 encoded text using returned text data
  98. # file path is passed to the method by the developer (default is the base filename in the URL if not specified)
  99. # return True on successful pull and write to disk
  100. # Tests: test_NETWORK.py :: test_http_get_text
  101. #------------------------------------------------------------------------------
  102. def get_txt_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
  103. try:
  104. import os # used for os.fsync() method in the write
  105. # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
  106. if not overwrite_existing:
  107. from Naked.toolshed.system import file_exists
  108. if file_exists(filepath):
  109. if not suppress_output:
  110. print("Download aborted. A local file with the requested filename exists on the path.")
  111. return False
  112. if (filepath == "" and len(self.url) > 1):
  113. filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
  114. if not suppress_output:
  115. sys.stdout.write("Downloading file from " + self.url + "...")
  116. sys.stdout.flush()
  117. response = requests.get(self.url, timeout=self.request_timeout, stream=True)
  118. self.res = response
  119. import codecs
  120. with codecs.open(filepath, mode='w', encoding="utf-8") as f: #write as text
  121. for chunk in response.iter_content(chunk_size=2048):
  122. chunk = chunk.decode('utf-8')
  123. f.write(chunk)
  124. f.flush()
  125. os.fsync(f.fileno()) # flush all internal buffers to disk
  126. if not suppress_output:
  127. print(" ")
  128. print("Download complete.")
  129. return True # return True if successful write
  130. except requests.exceptions.ConnectionError as ce:
  131. return False
  132. except Exception as e:
  133. if DEBUG_FLAG:
  134. 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)")
  135. raise e
  136. #------------------------------------------------------------------------------
  137. # [ head method ] (dictionary of strings)
  138. # HTTP HEAD request
  139. # returns a dictionary of the header strings
  140. # test for a specific header on either the response dictionary or the instance res property
  141. # Usage example:
  142. # content_type = instance.res['content-type']
  143. # Tests: test_NETWORK.py :: test_http_head
  144. #------------------------------------------------------------------------------
  145. def head(self):
  146. try:
  147. response = requests.head(self.url, timeout=self.request_timeout)
  148. self.res = response # assign the response object from requests to a property on the instance of HTTP class
  149. return response.headers
  150. except requests.exceptions.ConnectionError as ce:
  151. return False
  152. except Exception as e:
  153. if DEBUG_FLAG:
  154. sys.stderr.write("Naked Framework Error: Unable to perform a HEAD request with the head() method (Naked.toolshed.network.py).")
  155. raise e
  156. #------------------------------------------------------------------------------
  157. # [ post method ] (string)
  158. # HTTP POST request for text
  159. # returns text from the URL as a string
  160. #------------------------------------------------------------------------------
  161. def post(self, follow_redirects=True):
  162. try:
  163. response = requests.post(self.url, timeout=self.request_timeout, allow_redirects=follow_redirects)
  164. self.res = response # assign the response object from requests to a property on the instance of HTTP class
  165. return response.text
  166. except requests.exceptions.ConnectionError as ce:
  167. return False
  168. except Exception as e:
  169. if DEBUG_FLAG:
  170. sys.stderr.exit("Naked Framework Error: Unable to perform a POST request with the post() method (Naked.toolshed.network.py).")
  171. raise e
  172. #------------------------------------------------------------------------------
  173. # [ post_bin method ] (binary data)
  174. # HTTP POST request for binary data
  175. # returns binary data from the URL
  176. #------------------------------------------------------------------------------
  177. def post_bin(self):
  178. try:
  179. response = requests.post(self.url, timeout=self.request_timeout)
  180. self.res = response # assign the response object from requests to a property on the instance of HTTP class
  181. return response.content
  182. except requests.exceptions.ConnectionError as ce:
  183. return False
  184. except Exception as e:
  185. if DEBUG_FLAG:
  186. sys.stderr.exit("Naked Framework Error: Unable to perform POST request with the post_bin() method (Naked.toolshed.network.py).")
  187. raise e
  188. #------------------------------------------------------------------------------
  189. # [ post_bin_write_file method ] (boolean = success of write)
  190. # HTTP POST request, write binary file with the response data
  191. # default filepath is the basename of the URL file, may be set by passing an argument to the method
  192. # returns a boolean that indicates the success of the file write
  193. #------------------------------------------------------------------------------
  194. def post_bin_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
  195. try:
  196. import os # used for os.fsync() method in the write
  197. # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
  198. if not overwrite_existing:
  199. from Naked.toolshed.system import file_exists
  200. if file_exists(filepath):
  201. if not suppress_output:
  202. print("Download aborted. A local file with the requested filename exists on the path.")
  203. return False
  204. if (filepath == "" and len(self.url) > 1):
  205. filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
  206. if not suppress_output:
  207. sys.stdout.write("Downloading file from " + self.url + "...") #provide information about the download to user
  208. sys.stdout.flush()
  209. response = requests.post(self.url, timeout=self.request_timeout, stream=True)
  210. self.res = response
  211. with open(filepath, 'wb') as f: # write as binary data
  212. for chunk in response.iter_content(chunk_size=2048):
  213. f.write(chunk)
  214. f.flush()
  215. os.fsync(f.fileno()) # flush all internal buffers to disk
  216. if not suppress_output:
  217. print(" ")
  218. print("Download complete.") # provide user with completion information
  219. return True # return True if successful write
  220. except requests.exceptions.ConnectionError as ce:
  221. return False
  222. except Exception as e:
  223. if DEBUG_FLAG:
  224. 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)")
  225. raise e
  226. #------------------------------------------------------------------------------
  227. # [ post_txt_write_file method ] (boolean = success of file write)
  228. # HTTP POST request, write utf-8 encoded text file with the response data
  229. # default filepath is the basename of the URL file, may be set by passing an argument to the method
  230. # returns a boolean that indicates the success of the file write
  231. #------------------------------------------------------------------------------
  232. def post_txt_write_file(self, filepath="", suppress_output = False, overwrite_existing = False):
  233. try:
  234. import os # used for os.fsync() method in the write
  235. # Confirm that the file does not exist and prevent overwrite if it does (unless developer indicates otherwise)
  236. if not overwrite_existing:
  237. from Naked.toolshed.system import file_exists
  238. if file_exists(filepath):
  239. if not suppress_output:
  240. print("Download aborted. A local file with the requested filename exists on the path.")
  241. return False
  242. if (filepath == "" and len(self.url) > 1):
  243. filepath = self.url.split('/')[-1] # use the filename from URL and working directory as default if not specified
  244. if not suppress_output:
  245. sys.stdout.write("Downloading file from " + self.url + "...") #provide information about the download to user
  246. sys.stdout.flush()
  247. response = requests.post(self.url, timeout=self.request_timeout, stream=True)
  248. self.res = response
  249. import codecs
  250. with codecs.open(filepath, mode='w', encoding="utf-8") as f: # write as binary data
  251. for chunk in response.iter_content(chunk_size=2048):
  252. chunk = chunk.decode('utf-8')
  253. f.write(chunk)
  254. f.flush()
  255. os.fsync(f.fileno()) # flush all internal buffers to disk
  256. if not suppress_output:
  257. print(" ")
  258. print("Download complete.") # provide user with completion information
  259. return True # return True if successful write
  260. except requests.exceptions.ConnectionError as ce:
  261. return False
  262. except Exception as e:
  263. if DEBUG_FLAG:
  264. 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)")
  265. raise e
  266. #------------------------------------------------------------------------------
  267. # [ response method ]
  268. # getter method for the requests library object that is assigned as a property
  269. # on the HTTP class after a HTTP request method is run (e.g. get())
  270. # Note: must run one of the HTTP request verbs to assign this property before use of getter (=None by default)
  271. # Tests: test_NETWORK.py :: test_http_get_response_check
  272. #------------------------------------------------------------------------------
  273. def response(self):
  274. try:
  275. return self.res
  276. except Exception as e:
  277. if DEBUG_FLAG:
  278. sys.stderr.write("Naked Framework Error: Unable to return the response from your HTTP request with the response() method (Naked.toolshed.network.py).")
  279. raise e
  280. #------------------------------------------------------------------------------
  281. # [ get_status_ok method ] (boolean)
  282. # return boolean whether HTTP response was in 200 status code range for GET request
  283. # Note: this method runs its own GET request, does not need to be run separately
  284. # Tests: test_NETWORK.py ::
  285. #------------------------------------------------------------------------------
  286. def get_status_ok(self):
  287. try:
  288. self.get() #run the get request
  289. if self.res and self.res.status_code:
  290. return (self.res.status_code == requests.codes.ok)
  291. else:
  292. return False
  293. except requests.exceptions.ConnectionError as ce:
  294. return False
  295. except Exception as e:
  296. if DEBUG_FLAG:
  297. sys.stderr.write("Naked Framework Error: Unable to obtain the HTTP status with the get_status_ok() method (Naked.toolshed.network.py).")
  298. raise e
  299. #------------------------------------------------------------------------------
  300. # [ post_status_ok method ] (boolean)
  301. # return boolean whether HTTP response was in 200 status code range for POST request
  302. # Note: method runs its own post method, not necessary to run separately
  303. #------------------------------------------------------------------------------
  304. def post_status_ok(self):
  305. try:
  306. self.post() #run the post request
  307. if self.res and self.res.status_code:
  308. return (self.res.status_code == requests.codes.ok)
  309. else:
  310. return False
  311. except requests.exceptions.ConnectionError as ce:
  312. return False
  313. except Exception as e:
  314. if DEBUG_FLAG:
  315. sys.stderr.write("Naked Framework Error: Unable to obtain the HTTP status with the post_status_ok() method (Naked.toolshed.network.py).")
  316. raise e
  317. if __name__ == '__main__':
  318. pass
  319. #------------------------------------------------------------------------------
  320. # HTTP GET 1
  321. #------------------------------------------------------------------------------
  322. # http = HTTP("http://www.google.com")
  323. # data = http.get()
  324. # print(data)
  325. # from Naked.toolshed.file import FileWriter
  326. # w = FileWriter("testfile.txt")
  327. # w.write_utf8(data)
  328. #------------------------------------------------------------------------------
  329. # HTTP GET 2
  330. #------------------------------------------------------------------------------
  331. # http = HTTP()
  332. # http.url = "http://www.google.com"
  333. # print(http.get())