Advertisement
Guest User

Untitled

a guest
May 25th, 2017
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.92 KB | None | 0 0
  1. import logging
  2. import urllib.request
  3. from socket import timeout
  4. import StringIO
  5. import gzip
  6. import magic
  7.  
  8. from lxml import etree
  9. from PyQt5.QtCore import (QByteArray, QCoreApplication, QSettings, QThread,
  10. QTimer, pyqtSignal)
  11. from PyQt5.QtGui import QIcon
  12. from PyQt5.QtWidgets import (QDialog, QHBoxLayout, QLabel, QLineEdit,
  13. QListWidget, QPushButton, QVBoxLayout)
  14.  
  15.  
  16. class SearchCity(QDialog):
  17. id_signal = pyqtSignal([tuple])
  18. city_signal = pyqtSignal([tuple])
  19. country_signal = pyqtSignal([tuple])
  20.  
  21. def __init__(self, accurate_url, appid, parent=None):
  22. super(SearchCity, self).__init__(parent)
  23. self.settings = QSettings()
  24. self.delay = 1000
  25. self.search_string = self.tr('Searching...')
  26. self.timer = QTimer()
  27. self.accurate_url = accurate_url
  28. self.suffix = '&type=like&mode=xml' + appid
  29. self.layout = QVBoxLayout()
  30. self.lineLayout = QHBoxLayout()
  31. self.buttonSearch = QPushButton()
  32. self.buttonSearch.setIcon(QIcon(':/find'))
  33. self.buttonSearch.clicked.connect(self.search)
  34. self.line_search = QLineEdit(QCoreApplication.translate(
  35. 'Search city dialogue', 'Start typing the city...', ''))
  36. self.line_search.selectAll()
  37. self.listWidget = QListWidget()
  38. self.status = QLabel()
  39. self.lineLayout.addWidget(self.line_search)
  40. self.lineLayout.addWidget(self.buttonSearch)
  41. self.layout.addLayout(self.lineLayout)
  42. self.layout.addWidget(self.listWidget)
  43. self.layout.addWidget(self.status)
  44. self.buttonLayout = QHBoxLayout()
  45. self.buttonLayout.addStretch()
  46. self.buttonOk = QPushButton(self.tr('&Ok'))
  47. self.buttonOk.setEnabled(False)
  48. self.buttonCancel = QPushButton(self.tr('&Cancel'))
  49. self.buttonLayout.addWidget(self.buttonOk)
  50. self.buttonLayout.addWidget(self.buttonCancel)
  51. self.layout.addLayout(self.buttonLayout)
  52. self.setMinimumWidth(int(len(self.line_search.text())*20))
  53. self.setLayout(self.layout)
  54. self.line_search.returnPressed.connect(self.search)
  55. self.line_search.textChanged.connect(self.timer_run)
  56. self.buttonOk.clicked.connect(self.accept)
  57. self.buttonCancel.clicked.connect(self.reject)
  58. self.listWidget.itemSelectionChanged.connect(self.buttonCheck)
  59. self.listWidget.itemDoubleClicked['QListWidgetItem *'].connect(
  60. self.accept)
  61. self.restoreGeometry(self.settings.value("SearchCity/Geometry",
  62. QByteArray()))
  63. self.timer_search = QTimer(self)
  64. self.timer_search.timeout.connect(self.search)
  65. self.setWindowTitle(QCoreApplication.translate('Window title',
  66. 'Find a city', 'City search dialogue'))
  67.  
  68. def timer_run(self):
  69. self.timer_search.start(1000)
  70.  
  71. def closeEvent(self, event):
  72. self.settings.setValue("SearchCity/Geometry", self.saveGeometry())
  73.  
  74. def moveEvent(self, event):
  75. self.settings.setValue("SearchCity/Geometry", self.saveGeometry())
  76.  
  77. def resizeEvent(self, event):
  78. self.settings.setValue("SearchCity/Geometry", self.saveGeometry())
  79.  
  80. def buttonCheck(self):
  81. '''Enable OK button if an item is selected.'''
  82. row = self.listWidget.currentRow()
  83. item = self.listWidget.item(row)
  84. if item is not None:
  85. self.buttonOk.setEnabled(True)
  86.  
  87. def accept(self):
  88. row = self.listWidget.currentRow()
  89. item = self.listWidget.item(row)
  90. if item is not None:
  91. selected_city = item.text()
  92. city_list = selected_city.split(' - ')
  93. for c in range(len(city_list)):
  94. city_list[c] = city_list[c].strip()
  95. id_ = 'ID', city_list[0]
  96. city = 'City', city_list[1]
  97. country = 'Country', city_list[2]
  98. self.id_signal[tuple].emit(id_)
  99. self.city_signal[tuple].emit(city)
  100. self.country_signal[tuple].emit(country)
  101. QDialog.accept(self)
  102.  
  103. def thread_terminate(self):
  104. if hasattr(self, 'workThread'):
  105. if self.workThread.isRunning():
  106. self.workThread.terminate()
  107.  
  108. def search(self):
  109. self.timer_search.stop()
  110. self.city = (self.line_search.text())
  111. self.thread_terminate()
  112. if len(self.city) < 3:
  113. self.status.setText(self.tr('Please type more than three letters'))
  114. return
  115. self.lista = []
  116. self.errorStatus = False
  117. self.buttonOk.setEnabled(False)
  118. self.listWidget.clear()
  119. self.status.setText(self.search_string)
  120. self.workThread = WorkThread(self.accurate_url, self.city, self.suffix)
  121. self.workThread.setTerminationEnabled(True)
  122. self.workThread.city_signal['QString'].connect(self.addlist)
  123. self.workThread.finished.connect(self.result)
  124. self.workThread.error['QString'].connect(self.error)
  125. self.workThread.searching['QString'].connect(self.searching)
  126. self.workThread.started.connect(self.thread_started)
  127. self.timer.singleShot(self.delay, self.threadstart)
  128.  
  129. def searching(self, message):
  130. '''Display a status message when searching takes a while'''
  131. self.status.setText(message)
  132.  
  133. def thread_started(self):
  134. '''Force the "searching" status message'''
  135. self.status.setText(self.search_string)
  136.  
  137. def threadstart(self):
  138. self.workThread.start()
  139.  
  140. def addlist(self, city):
  141. logging.debug('Found: ' + str(city))
  142. if city not in self.lista:
  143. self.lista.append(city)
  144. self.errorStatus = False
  145.  
  146. def error(self, e):
  147. self.delay = 2000
  148. logging.error(e)
  149. self.status.setText(e)
  150. self.adjustSize()
  151. self.errorStatus = True
  152.  
  153. def result(self):
  154. if self.errorStatus:
  155. return
  156. if len(self.line_search.text()) < 3:
  157. self.thread_terminate()
  158. self.status.clear()
  159. return
  160. self.delay = 1000
  161. # Clear the listWidget elements from an interrupted thread
  162. self.listWidget.clear()
  163. self.listWidget.addItems(self.lista)
  164. number_cities = len(self.lista)
  165. cities_text = ''
  166. if number_cities == 0:
  167. cities_text = self.tr('No results')
  168. elif number_cities == 1:
  169. cities_text = self.tr('Found {0} city').format(number_cities)
  170. elif number_cities > 1:
  171. cities_text = self.tr('Found {0} cities').format(number_cities)
  172. self.status.setText(cities_text)
  173.  
  174.  
  175. class WorkThread(QThread):
  176. error = pyqtSignal(['QString'])
  177. city_signal = pyqtSignal(['QString'])
  178. searching = pyqtSignal(['QString'])
  179.  
  180. def __init__(self, accurate_url, city, suffix, parent=None):
  181. QThread.__init__(self, parent)
  182. self.accurate_url = accurate_url
  183. # Search in any language
  184. self.city = city # self.encode_utf8(city)
  185. self.suffix = suffix
  186. self.tentatives = 1
  187. self.settings = QSettings()
  188.  
  189. def run(self):
  190. use_proxy = self.settings.value('Proxy') or 'False'
  191. use_proxy = eval(use_proxy)
  192. proxy_auth = self.settings.value(
  193. 'Use_proxy_authentification') or 'False'
  194. proxy_auth = eval(proxy_auth)
  195. if use_proxy:
  196. proxy_url = self.settings.value('Proxy_url')
  197. proxy_port = self.settings.value('Proxy_port')
  198. proxy_tot = 'http://' + ':' + proxy_port
  199. if proxy_auth:
  200. proxy_user = self.settings.value('Proxy_user')
  201. proxy_password = self.settings.value('Proxy_pass')
  202. proxy_tot = ('http://' + proxy_user + ':' + proxy_password +
  203. '@' + proxy_url + ':' + proxy_port)
  204. proxy = urllib.request.ProxyHandler({"http": proxy_tot})
  205. auth = urllib.request.HTTPBasicAuthHandler()
  206. opener = urllib.request.build_opener(
  207. proxy, auth, urllib.request.HTTPHandler)
  208. urllib.request.install_opener(opener)
  209. else:
  210. proxy_handler = urllib.request.ProxyHandler({})
  211. opener = urllib.request.build_opener(proxy_handler)
  212. urllib.request.install_opener(opener)
  213. error_message = self.tr('Data error, please try again later\n'
  214. 'or modify the name of the city')
  215. self.lista = []
  216. if self.city == '':
  217. return
  218. try:
  219. logging.debug(
  220. self.accurate_url + repr(self.city.encode('utf-8')).replace(
  221. "b'", "").replace("\\x", "%").replace(
  222. "'", "").replace(' ', '%20') + self.suffix)
  223. logging.debug('City before utf8 encode :' + self.accurate_url +
  224. self.city + self.suffix)
  225. req = urllib.request.urlopen(
  226. self.accurate_url + repr(self.city.encode('utf-8')).replace(
  227. "b'", "").replace("\\x", "%").replace(
  228. "'", "").replace(' ', '%20') + self.suffix, timeout=5)
  229. page = req.read()
  230. if magic.from_buffer(page, mime = True) == "application/x-gzip":
  231. gzipped_page = gzip.GzipFile(fileobj = StringIO.StringIO(page))
  232. page = gzipped_page
  233. tree = etree.fromstring(page)
  234. except timeout:
  235. if self.tentatives == 10:
  236. logging.error(error_message)
  237. return
  238. else:
  239. self.tentatives += 1
  240. searching_message = self.tr('Please wait, searching...')
  241. logging.debug(searching_message)
  242. self.searching['QString'].emit(searching_message)
  243. self.run()
  244. except (urllib.error.HTTPError, urllib.error.URLError) as error:
  245. code = ''
  246. if hasattr(error, 'code'):
  247. code = str(error.code)
  248. m_error = (self.tr('Error: ') + code + ' ' + str(error.reason) +
  249. self.tr('\nTry again later'))
  250. if self.tentatives == 10:
  251. self.error['QString'].emit(m_error)
  252. return
  253. else:
  254. self.tentatives += 1
  255. logging.debug('Tries: ' + str(self.tentatives))
  256. self.run()
  257. # No result
  258. try:
  259. if int(tree[1].text) == 0:
  260. logging.debug('Number of cities: 0')
  261. if self.tentatives == 10:
  262. return
  263. else:
  264. self.tentatives += 1
  265. logging.debug('Tries: ' + str(self.tentatives))
  266. logging.debug('Try to retreive city information...')
  267. self.run()
  268. except:
  269. return
  270. for i in range(int(tree[1].text)):
  271. city = tree[3][i][0].get('name')
  272. country = tree[3][i][0][1].text
  273. id_ = tree[3][i][0].get('id')
  274. if int(id_) == 0:
  275. logging.error('Error ID: ' + str(id_))
  276. if self.tentatives == 10:
  277. self.error['QString'].emit(error_message)
  278. return
  279. else:
  280. self.tentatives += 1
  281. logging.debug('Tries: ' + str(self.tentatives))
  282. logging.debug('Try to retrieve city information...')
  283. # Try with a fuzzy city name
  284. if city != '':
  285. logging.info('Change search to:' + city)
  286. self.city = repr(city.encode('utf-8')).replace(
  287. "b'", "").replace("\\x", "%").replace(
  288. "'", "").replace(' ', '%20')
  289. self.run()
  290. if city == '' or country is None:
  291. if self.tentatives == 10:
  292. self.error['QString'].emit(error_message)
  293. return
  294. else:
  295. self.tentatives += 1
  296. logging.debug('Tries: ' + str(self.tentatives))
  297. logging.debug('Try to retrieve city information...')
  298. self.run()
  299. try:
  300. if id_ == '0':
  301. continue
  302. place = (id_ + ' - ' + city + ' - ' + country)
  303. if place in self.lista:
  304. continue
  305. self.lista.append(place)
  306. except:
  307. logging.critical('An error has occured:')
  308. logging.critical('ID' + str(id_))
  309. logging.critical('City' + str(city))
  310. logging.critical('Country' + str(country))
  311. return
  312. for i in self.lista:
  313. self.city_signal['QString'].emit(i)
  314. logging.debug('City thread done')
  315. return
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement