memoQProject.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. from suds.client import Client
  2. import datetime
  3. import os
  4. import memoQFile
  5. from base64 import b64decode, b64encode
  6. import json
  7. class Languages(object):
  8. """Encapsulates project languages."""
  9. def __init__(self):
  10. self.target = []
  11. self.source = None
  12. class Project(object):
  13. """Encapsulates basic project information."""
  14. def __init__(self):
  15. self.__guid = None
  16. now = datetime.datetime.now()
  17. self.name = 'Test_{}'.format(str(now).replace(":", "-"))
  18. self.domain = "Python"
  19. self.documents = None
  20. self.languages = Languages()
  21. self.deadline = now + datetime.timedelta(days=2)
  22. def get_project_guid(self):
  23. return self.__guid
  24. def set_project_guid(self, value):
  25. self.__guid = value
  26. def populate_project_info(self, projectInfo):
  27. """Populates name, domain, languages, deadline from project information as received
  28. from memoQ server."""
  29. if projectInfo != None:
  30. self.name = projectInfo['Name']
  31. self.domain = projectInfo['Domain']
  32. self.languages.target = [
  33. x for x in projectInfo['TargetLanguageCodes'].string]
  34. self.languages.source = projectInfo['SourceLanguageCode']
  35. self.deadline = projectInfo['Deadline']
  36. class MemoQProject(object):
  37. """Client for memoQ Server projects API."""
  38. def __init__(self):
  39. with open("config.json") as json_file:
  40. self.config = json.load(json_file)
  41. if self.config["api_base_url"] != "":
  42. api_url = self.config["api_base_url"] + \
  43. "/memoqservices/ServerProject?wsdl"
  44. self.client = Client(api_url)
  45. self.project = Project()
  46. def __repr__(self):
  47. if self.project.get_project_guid() != None:
  48. return "{} - {}\n{} - {}\n{}".format(self.project.name, self.project.get_project_guid(), self.project.languages.source, (", ").join([x for x in self.project.languages.target]), str(self.project.deadline))
  49. else:
  50. return "No project!"
  51. def get_project_by_domain(self, domain):
  52. """Gets first project of given domain name."""
  53. filter = self.client.factory.create(
  54. '{http://kilgray.com/memoqservices/2007}ServerProjectListFilter')
  55. filter.Domain = domain
  56. projects = self.client.service.ListProjects(filter)
  57. if projects:
  58. self.project.set_project_guid(projects[0][0]['ServerProjectGuid'])
  59. self.project.populate_project_info(projects[0][0])
  60. else:
  61. self.project.set_project_guid(None)
  62. def get_project_by_guid(self, guid):
  63. """Gets project information for project of given guid."""
  64. project_info = self.client.service.GetProject(guid)
  65. if project_info != None:
  66. self.project.set_project_guid(guid)
  67. self.project.populate_project_info(project_info)
  68. else:
  69. self.project.set_project_guid(None)
  70. def template_project_options(self, template_guid):
  71. """Needs guid of memoQ project template. project.languages.source must be set.
  72. Returns options needed for creating memoQ project from template."""
  73. if self.project.languages.source != None:
  74. options = self.client.factory.create(
  75. '{http://kilgray.com/memoqservices/2007}TemplateBasedProjectCreateInfo')
  76. options.TemplateGuid = template_guid
  77. options.Name = self.project.name
  78. if self.project.languages.source != "":
  79. options.SourceLanguageCode = self.project.languages.source
  80. else:
  81. print("project.languages.source must be set!")
  82. return None
  83. options.Domain = self.project.domain
  84. options.CreatorUser = self.config["creator_guid"]
  85. return options
  86. else:
  87. return None
  88. def create_project_from_template(self, template_guid=None, options=None):
  89. """Creates memoQ project using predefined options when
  90. provided with template_guid or using provided options.
  91. Sets new project as active project on success."""
  92. if template_guid != None:
  93. options = self.template_project_options(template_guid)
  94. if options != None:
  95. result = self.client.service.CreateProjectFromTemplate(options)
  96. if result.ResultStatus == "Success":
  97. self.get_project_by_guid(result.ProjectGuid)
  98. else:
  99. self.project.set_project_guid(None)
  100. def project_options(self):
  101. """Returns options needed for creating memoQ project. project.languages.source and project.languages.target must be set."""
  102. if len(self.project.languages.target) and self.project.languages.source != None:
  103. options = self.client.factory.create(
  104. '{http://kilgray.com/memoqservices/2007}ServerProjectDesktopDocsCreateInfo')
  105. options.Name = self.project.name
  106. if self.project.languages.source != "":
  107. options.SourceLanguageCode = self.project.languages.source
  108. else:
  109. print("project.languages.source must be set!")
  110. return None
  111. if len(self.project.languages.target):
  112. options.TargetLanguageCodes.string = self.project.languages.target
  113. else:
  114. print("project.languages.target must be set!")
  115. return None
  116. options.Deadline = self.project.deadline
  117. options.RecordVersionHistory = True
  118. options.CreatorUser = self.config["creator_guid"]
  119. resources = self.client.factory.create(
  120. '{http://schemas.datacontract.org/2004/07/MemoQServices}ServerProjectResourcesInPackages')
  121. options.PackageResourceHandling.value = resources.LinkRemote
  122. return options
  123. else:
  124. return None
  125. def create_project(self, options=None):
  126. """Creates memoQ project using predefined or provided options.
  127. Sets new project as active project on success."""
  128. if options == None:
  129. options = self.project_options()
  130. if options != None:
  131. project_guid = self.client.service.CreateProject2(options)
  132. if project_guid != None:
  133. self.get_project_by_guid(project_guid)
  134. else:
  135. self.project.set_project_guid(None)
  136. def import_document(self, path):
  137. """Uploads and then imports given file to active project for all target languages.
  138. Returns true on success."""
  139. file_client = memoQFile.MemoQFile()
  140. file_guid = file_client.upload_file(path)
  141. if file_guid == None:
  142. return False
  143. langs = self.client.factory.create(
  144. '{http://kilgray.com/memoqservices/2007}targetLangCodes')
  145. langs.string = self.project.languages.target
  146. result = self.client.service.ImportTranslationDocument(
  147. self.project.get_project_guid(), file_guid, langs)
  148. if result != None:
  149. return True
  150. else:
  151. return False
  152. def get_project_documents(self):
  153. """Gets list of documents from active project."""
  154. options = self.client.factory.create(
  155. '{http://kilgray.com/memoqservices/2007}ListServerProjectTranslationDocument2Options')
  156. options.FillInAssignmentInformation = True
  157. if self.project.get_project_guid() != None:
  158. self.documents = self.client.service.ListProjectTranslationDocuments2(
  159. self.project.get_project_guid(), options)
  160. def document_guids(self):
  161. """Returns guids of documents from active project."""
  162. if self.documents == None:
  163. self.get_project_documents()
  164. return [x.DocumentGuid for x in self.documents[0]]
  165. def print_documents(self):
  166. """Prints basic information on documents from active project."""
  167. if self.documents == None:
  168. self.get_project_documents()
  169. for document in self.documents[0]:
  170. print("{} ({}) - {}\n".format(document.DocumentName,
  171. document.TargetLangCode, document.DocumentGuid))
  172. def export_documents(self, path):
  173. """Exports all documents from active project to given path.
  174. Prints path to each file on success and returns true."""
  175. if self.project.get_project_guid() == None:
  176. return "No project!"
  177. export_results = []
  178. for guid in self.document_guids():
  179. export_results.append(
  180. self.client.service.ExportTranslationDocument(self.project.get_project_guid(), guid))
  181. file_client = memoQFile.MemoQFile()
  182. if len(export_results):
  183. for document in export_results:
  184. print(file_client.download_file(path, document.FileGuid))
  185. return True
  186. else:
  187. return False
  188. def export_documents2(self, path):
  189. """Exports all documents from active project to given path using extended method.
  190. Prints path to each file on success and returns true."""
  191. if self.project.get_project_guid() == None:
  192. return "No project!"
  193. options = self.client.factory.create(
  194. '{http://kilgray.com/memoqservices/2007}DocumentExportOptions')
  195. options.CopySourceToEmptyTarget = True
  196. export_results = []
  197. for guid in self.document_guids():
  198. export_results.append(self.client.service.ExportTranslationDocument2(
  199. self.project.get_project_guid(), guid, options))
  200. file_client = memoQFile.MemoQFile()
  201. if len(export_results):
  202. for document in export_results:
  203. print(file_client.download_file(path, document.FileGuid))
  204. return True
  205. else:
  206. return False
  207. def statistics_options(self):
  208. """Returns options for statistics."""
  209. options = self.client.factory.create(
  210. '{http://kilgray.com/memoqservices/2007}StatisticsOptions')
  211. options.Analysis_ProjectTMs = True
  212. options.Analysis_Homogenity = True
  213. options.ShowResultsPerFile = True
  214. options.RepetitionPreferenceOver100 = True
  215. statistics_algorithm = self.client.factory.create(
  216. '{http://schemas.datacontract.org/2004/07/MemoQServices}StatisticsAlgorithm')
  217. options.Algorithm.value = statistics_algorithm.MemoQ
  218. return options
  219. def run_statistics(self):
  220. """Returns statistics for all documents and language combinations of active project,
  221. none on failure."""
  222. options = self.statistics_options()
  223. statistics_format = self.client.factory.create(
  224. '{http://schemas.datacontract.org/2004/07/MemoQServices}StatisticsResultFormat')
  225. languages = self.client.factory.create(
  226. '{http://kilgray.com/memoqservices/2007}targetLangCodes')
  227. languages.string = self.project.languages.target
  228. try:
  229. stats = self.client.service.GetStatisticsOnProject(
  230. self.project.get_project_guid(), languages, options, statistics_format.CSV_MemoQ)
  231. if stats.ResultStatus == "Success":
  232. return stats
  233. else:
  234. return None
  235. except Exception as e:
  236. print(str(e))
  237. def save_statistics(self, path):
  238. """Saves statictis to given path (one file per language combination).
  239. Returns path to statistics file(s)."""
  240. statistics = self.run_statistics()
  241. if statistics != None:
  242. for stat in statistics.ResultsForTargetLangs.StatisticsResultForLang:
  243. output_file = '{}_{}.csv'.format(
  244. stat.TargetLangCode, self.project.name)
  245. with open(output_file, 'wb') as target:
  246. target.write(b64decode(stat.ResultData))
  247. filename = '{}_{}.csv'.format(
  248. stat.TargetLangCode, self.project.name)
  249. output_file = os.path.join(path, filename)
  250. with open(output_file, 'wb') as target:
  251. # Statistics are base64 and utf-16 encoded, so we need to
  252. # decode first
  253. stat_data = b64decode(stat.ResultData).decode("utf-16")
  254. # Changing delimiter to ,
  255. stat_data = stat_data.replace(";", ",")
  256. target.write(stat_data.encode("utf-8"))
  257. return output_file
  258. def delete(self):
  259. """Deletes active project permamently. WARNING! Not possible to recover!"""
  260. self.client.service.DeleteProject(self.project.get_project_guid())