network.pyx 19 KB

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