Browse Source

first commit

Piotr Czajkowski 7 years ago
commit
3f6c77c396
15 changed files with 1389 additions and 0 deletions
  1. 11 0
      README.md
  2. 5 0
      __init__.py
  3. 4 0
      config.json
  4. 49 0
      memoQFile.py
  5. 20 0
      memoQFileTest.py
  6. 296 0
      memoQProject.py
  7. 279 0
      memoQProjectTest.py
  8. 73 0
      memoQResource.py
  9. 94 0
      memoQResourceTest.py
  10. 194 0
      memoQSecurity.py
  11. 194 0
      memoQSecurityTest.py
  12. 74 0
      memoQTM.py
  13. 72 0
      memoQTMTest.py
  14. 1 0
      testFiles/test.txt
  15. 23 0
      testFiles/testConfig.json

+ 11 - 0
README.md

@@ -0,0 +1,11 @@
+# Client for memoQ server Web Service API
+
+This is a group of packages for Python to interact with [memoQ server Web Service API](https://www.memoq.com/en/the-memoq-apis/memoq-server-web-service-api). It's using Suds SOAP client, I recommend downloading [Satiani's version](https://github.com/satiani/suds) as it fixes problem with recursion.
+
+It's quite heavily customized to my own needs in terms of settings (project creation, statistics), so you may want to check some of the methods before running them. **All exceptions returned by the server are ignored.**
+
+You may use them all as single package or as standalone ones. Start with adjusting *config.json*, especially "api_base_url". If you want your projects to be created as user other than built-in Administrator change "creator_guid" as well.
+
+Every method in each package is unit tested. However, I'm aware that not all possible cases are covered. Before running tests on your side you'll need to change few things in *testFiles/testConfig.json* to align it with your environment. Especially items starting with *valid*.
+
+**I've created this for my experiments and never used it on production environment. You're free to use it however you wish, but I take no responsibility for any possible damage caused by it.**

+ 5 - 0
__init__.py

@@ -0,0 +1,5 @@
+import memoQFile
+import memoQProject
+import memoQResource
+import memoQSecurity
+import memoQTM

+ 4 - 0
config.json

@@ -0,0 +1,4 @@
+{
+    "api_base_url" : "http://localhost:8080",
+    "creator_guid" : "00000000-0000-0000-0001-000000000001"
+}

+ 49 - 0
memoQFile.py

@@ -0,0 +1,49 @@
+from suds.client import Client
+from base64 import b64decode, b64encode
+import os
+import json
+
+
+class MemoQFile(object):
+    """Client for memoQ File management API."""
+
+    def __init__(self):
+        with open("config.json") as json_file:
+            self.config = json.load(json_file)
+
+        if self.config["api_base_url"] != "":
+            apiURL = self.config["api_base_url"] + \
+                "/memoqservices/filemanager?wdsl"
+            self.client = Client(apiURL)
+
+    def download_file(self, path, guid):
+        """Downloads file of given guid from memoQ Server to specified path. Returns full path of downloaded file."""
+        chunk_size = 1000000
+        start, filename, filesize = self.client.service.BeginChunkedFileDownload(
+            guid, False)
+        file_bytes_left = filesize[1]
+        output_filename = os.path.join(path, filename[1])
+        output = open(output_filename, 'wb')
+        while file_bytes_left > 0:
+            chunk = self.client.service.GetNextFileChunk(start[1], chunk_size)
+            output.write(b64decode(chunk))
+            file_bytes_left -= len(chunk)
+        output.close()
+        self.client.service.EndChunkedFileDownload(start[1])
+        return output_filename
+
+    def upload_file(self, file_path, chunk_size=1024):
+        """Uploads given file to memoQ Server. Returns guid of uploaded file."""
+        file_to_send = open(file_path, 'rb')
+        file_guid = self.client.service.BeginChunkedFileUpload(
+            file_path, False)
+        while True:
+            data = b64encode(file_to_send.read(chunk_size))
+            if not data:
+                break
+            else:
+                self.client.service.AddNextFileChunk(file_guid, data)
+
+        self.client.service.EndChunkedFileUpload(file_guid)
+        file_to_send.close()
+        return file_guid

+ 20 - 0
memoQFileTest.py

@@ -0,0 +1,20 @@
+import unittest
+import memoQFile
+import os
+
+
+class memoQFileTest(unittest.TestCase):
+
+    def test_upload_download_file(self):
+        test = memoQFile.MemoQFile()
+
+        file_guid = test.upload_file("testFiles/test.txt")
+        self.assertNotEqual(file_guid, None, "Guid shouldn't equal none!")
+
+        file_path = test.download_file(".", file_guid)
+        self.assertTrue(os.path.isfile(file_path), "File should exist!")
+
+        os.remove(file_path)
+
+if __name__ == "__main__":
+    unittest.main()

+ 296 - 0
memoQProject.py

@@ -0,0 +1,296 @@
+from suds.client import Client
+import datetime
+import os
+import memoQFile
+from base64 import b64decode, b64encode
+import json
+
+
+class Languages(object):
+    """Encapsulates project languages."""
+
+    def __init__(self):
+        self.target = []
+        self.source = None
+
+
+class Project(object):
+    """Encapsulates basic project information."""
+
+    def __init__(self):
+        self.__guid = None
+        now = datetime.datetime.now()
+        self.name = 'Test_{}'.format(str(now).replace(":", "-"))
+        self.domain = "Python"
+        self.documents = None
+        self.languages = Languages()
+        self.deadline = now + datetime.timedelta(days=2)
+
+    def get_project_guid(self):
+        return self.__guid
+
+    def set_project_guid(self, value):
+        self.__guid = value
+
+    def populate_project_info(self, projectInfo):
+        """Populates name, domain, languages, deadline from project information as received
+        from memoQ server."""
+        if projectInfo != None:
+            self.name = projectInfo['Name']
+            self.domain = projectInfo['Domain']
+            self.languages.target.extend(
+                [x for x in projectInfo['TargetLanguageCodes'].string])
+            self.languages.source = projectInfo['SourceLanguageCode']
+            self.deadline = projectInfo['Deadline']
+
+
+class MemoQProject(object):
+    """Client for memoQ Server projects API."""
+
+    def __init__(self):
+        with open("config.json") as json_file:
+            self.config = json.load(json_file)
+
+        if self.config["api_base_url"] != "":
+            apiURL = self.config["api_base_url"] + \
+                "/memoqservices/ServerProject?wsdl"
+            self.client = Client(apiURL)
+
+        self.project = Project()
+
+    def __repr__(self):
+        if self.project.get_project_guid() != None:
+            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))
+        else:
+            return "No project!"
+
+    def get_project_by_domain(self, domain):
+        """Gets first project of given domain name."""
+        filter = self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}ServerProjectListFilter')
+        filter.Domain = domain
+
+        projects = self.client.service.ListProjects(filter)
+        if projects:
+            self.project.set_project_guid(projects[0][0]['ServerProjectGuid'])
+            self.project.populate_project_info(projects[0][0])
+        else:
+            self.project.set_project_guid(None)
+
+    def get_project_by_guid(self, guid):
+        """Gets project information for project of given guid."""
+        project_info = self.client.service.GetProject(guid)
+        if project_info != None:
+            self.project.set_project_guid(guid)
+            self.project.populate_project_info(project_info)
+        else:
+            self.project.set_project_guid(None)
+
+    def template_project_options(self, template_guid):
+        """Needs guid of memoQ project template.
+        Returns options needed for creating memoQ project from template."""
+        if self.project.languages.source != None:
+            options = self.client.factory.create(
+                '{http://kilgray.com/memoqservices/2007}TemplateBasedProjectCreateInfo')
+            options.TemplateGuid = template_guid
+            options.Name = self.project.name
+            options.SourceLanguageCode = self.project.languages.source
+            options.Domain = self.project.domain
+            options.CreatorUser = self.config["creator_guid"]
+            return options
+        else:
+            return None
+
+    def create_project_from_template(self, templateGuid):
+        """Creates memoQ project from given project template.
+        Sets new project as active project on success."""
+        options = self.template_project_options(templateGuid)
+        if options != None:
+            result = self.client.service.CreateProjectFromTemplate(options)
+            if result.ResultStatus == "Success":
+                self.get_project_by_guid(result.ProjectGuid)
+            else:
+                self.project.set_project_guid(None)
+
+    def project_options(self):
+        """Returns options needed for creating memoQ project."""
+        if len(self.project.languages.target) and self.project.languages.source != None:
+            options = self.client.factory.create(
+                '{http://kilgray.com/memoqservices/2007}ServerProjectDesktopDocsCreateInfo')
+            options.Name = self.project.name
+            options.SourceLanguageCode = self.project.languages.source
+            options.TargetLanguageCodes.string = self.project.languages.target
+            options.Deadline = self.project.deadline
+            options.RecordVersionHistory = True
+            options.CreatorUser = self.config["creator_guid"]
+
+            resources = self.client.factory.create(
+                '{http://schemas.datacontract.org/2004/07/MemoQServices}ServerProjectResourcesInPackages')
+            options.PackageResourceHandling.value = resources.LinkRemote
+            return options
+        else:
+            return None
+
+    def create_project(self):
+        """Creates memoQ project. Sets new project as active project on success."""
+        options = self.project_options()
+        if options != None:
+            project_guid = self.client.service.CreateProject2(options)
+            if project_guid != None:
+                self.get_project_by_guid(project_guid)
+            else:
+                self.project.set_project_guid(None)
+
+    def import_document(self, path):
+        """Uploads and then imports given file to active project for all target languages.
+        Returns true on success."""
+        file_client = memoQFile.MemoQFile()
+        file_guid = file_client.upload_file(path)
+        if file_guid == None:
+            return False
+
+        langs = self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}targetLangCodes')
+        langs.string = self.project.languages.target
+
+        result = self.client.service.ImportTranslationDocument(
+            self.project.get_project_guid(), file_guid, langs)
+        if result != None:
+            return True
+        else:
+            return False
+
+    def get_project_documents(self):
+        """Gets list of documents from active project."""
+        options = self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}ListServerProjectTranslationDocument2Options')
+        options.FillInAssignmentInformation = True
+
+        if self.project.get_project_guid() != None:
+            self.documents = self.client.service.ListProjectTranslationDocuments2(
+                self.project.get_project_guid(), options)
+
+    def document_guids(self):
+        """Returns guids of documents from active project."""
+        if self.documents == None:
+            self.get_project_documents()
+
+        return [x.DocumentGuid for x in self.documents[0]]
+
+    def print_documents(self):
+        """Prints basic information on documents from active project."""
+        if self.documents == None:
+            self.get_project_documents()
+
+        for document in self.documents[0]:
+            print("{} ({}) - {}\n".format(document.DocumentName,
+                                          document.TargetLangCode, document.DocumentGuid))
+
+    def export_documents(self, path):
+        """Exports all documents from active project to given path.
+        Prints path to each file on success and returns true."""
+        if self.project.get_project_guid() == None:
+            return "No project!"
+
+        if self.project.documents == None:
+            self.get_project_documents()
+
+        export_results = []
+        for guid in self.document_guids():
+            export_results.append(
+                self.client.service.ExportTranslationDocument(self.project.get_project_guid(), guid))
+
+        file_client = memoQFile.MemoQFile()
+        if len(export_results):
+            for document in export_results:
+                print(file_client.download_file(path, document.FileGuid))
+            return True
+        else:
+            return False
+
+    def export_documents2(self, path):
+        """Exports all documents from active project to given path using extended method.
+        Prints path to each file on success and returns true."""
+        if self.project.get_project_guid() == None:
+            return "No project!"
+
+        if self.documents == None:
+            self.get_project_documents()
+
+        options = self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}DocumentExportOptions')
+        options.CopySourceToEmptyTarget = True
+
+        export_results = []
+        for guid in self.document_guids():
+            export_results.append(self.client.service.ExportTranslationDocument2(
+                self.project.get_project_guid(), guid, options))
+
+        file_client = memoQFile.MemoQFile()
+        if len(export_results):
+            for document in export_results:
+                print(file_client.download_file(path, document.FileGuid))
+            return True
+        else:
+            return False
+
+    def statistics_options(self):
+        """Returns options for statistics."""
+        options = self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}StatisticsOptions')
+        options.Analysis_ProjectTMs = True
+        options.Analysis_Homogenity = True
+        options.ShowResultsPerFile = True
+        options.RepetitionPreferenceOver100 = True
+        statistics_algorithm = self.client.factory.create(
+            '{http://schemas.datacontract.org/2004/07/MemoQServices}StatisticsAlgorithm')
+        options.Algorithm.value = statistics_algorithm.MemoQ
+
+        return options
+
+    def run_statistics(self):
+        """Returns statistics for all documents and language combinations of active project,
+         none on failure."""
+        options = self.statistics_options()
+
+        statistics_format = self.client.factory.create(
+            '{http://schemas.datacontract.org/2004/07/MemoQServices}StatisticsResultFormat')
+        languages = self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}targetLangCodes')
+        languages.string = self.project.languages.target
+
+        try:
+            stats = self.client.service.GetStatisticsOnProject(
+                self.project.get_project_guid(), languages, options, statistics_format.CSV_MemoQ)
+            if stats.ResultStatus == "Success":
+                return stats
+            else:
+                return None
+        except Exception as e:
+            print(str(e))
+
+    def save_statistics(self, path):
+        """Saves statictis to given path (one file per language combination).
+        Returns path to statistics file(s)."""
+        statistics = self.run_statistics()
+        if statistics != None:
+            for stat in statistics.ResultsForTargetLangs.StatisticsResultForLang:
+                output_file = '{}_{}.csv'.format(
+                    stat.TargetLangCode, self.project.name)
+                with open(output_file, 'wb') as target:
+                    target.write(b64decode(stat.ResultData))
+                    filename = '{}_{}.csv'.format(
+                    stat.TargetLangCode, self.project.name)
+                output_file = os.path.join(path, filename)
+                with open(output_file, 'wb') as target:
+                    # Statistics are base64 and utf-16 encoded, so we need to
+                    # decode first
+                    stat_data = b64decode(stat.ResultData).decode("utf-16")
+                    # Changing delimiter to ,
+                    stat_data = stat_data.replace(";", ",")
+                    target.write(stat_data.encode("utf-8"))
+                return output_file
+
+    def delete(self):
+        """Deletes active project permamently. WARNING! Not possible to recover!"""
+        self.client.service.DeleteProject(self.project.get_project_guid())

+ 279 - 0
memoQProjectTest.py

@@ -0,0 +1,279 @@
+import unittest
+import memoQProject
+import json
+import os
+
+
+class MemoQProjectTest(unittest.TestCase):
+    """Tests for memoQProject module."""
+
+    def __init__(self, *args, **kwargs):
+        super(MemoQProjectTest, self).__init__(*args, **kwargs)
+        with open("testFiles/testConfig.json") as json_file:
+            self.config = json.load(json_file)
+
+    def test_get_project_by_domain(self):
+        """ Test for get_project_by_domain method."""
+        test = memoQProject.MemoQProject()
+
+        test.get_project_by_domain(self.config["valid_domain"])
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        test.get_project_by_domain(self.config["wrong_domain"])
+        self.assertEqual(test.project.get_project_guid(),
+                         None, "Guid should be none!")
+
+    def test_get_project_by_guid(self):
+        """ Test for get_project_by_guid method."""
+        test = memoQProject.MemoQProject()
+
+        valid_guid = "27e14066-0b73-44fc-a5ea-a828fed42e7f"
+        wrong_guid = "00000000-0000-0000-0000-000000000001"
+
+        test.get_project_by_guid(valid_guid)
+        self.assertEqual(test.project.get_project_guid(),
+                         valid_guid, "Guids don't match!")
+
+        test.get_project_by_guid(wrong_guid)
+        self.assertEqual(test.project.get_project_guid(),
+                         None, "Guid should be none!")
+
+    def test_template_project_options(self):
+        """ Test for template_project_options method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+
+        options = test.template_project_options(
+            self.config["project_template_guid"])
+
+        fake_options = test.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}TemplateBasedProjectCreateInfo')
+        fake_options.TemplateGuid = self.config["project_template_guid"]
+        fake_options.Name = test.project.name
+        fake_options.SourceLanguageCode = test.project.languages.source
+        fake_options.Domain = test.project.domain
+        fake_options.CreatorUser = self.config["creator_guid"]
+
+        self.assertEqual(options.Name, fake_options.Name,
+                         "Names should be equal!")
+        self.assertEqual(options.TemplateGuid, fake_options.TemplateGuid,
+                         "Template guids should be equal!")
+        self.assertEqual(options.Domain, fake_options.Domain,
+                         "Domains should be equal!")
+        self.assertEqual(options.SourceLanguageCode, fake_options.SourceLanguageCode,
+                         "Source language codes should be equal!")
+
+    def test_create_project_from_template(self):
+        """ Test for create_project_from_template method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+
+        test.create_project_from_template(self.config["project_template_guid"])
+
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        test.delete()
+
+    def test_project_options(self):
+        """ Test for project_options method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        options = test.project_options()
+
+        fake_options = test.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}ServerProjectDesktopDocsCreateInfo')
+        fake_options.Name = test.project.name
+        fake_options.SourceLanguageCode = test.project.languages.source
+        fake_options.TargetLanguageCodes.string = test.project.languages.target
+        fake_options.Deadline = test.project.deadline
+        fake_options.RecordVersionHistory = True
+        fake_options.CreatorUser = self.config["creator_guid"]
+
+        self.assertEqual(options.Name, fake_options.Name,
+                         "Names should be equal!")
+        self.assertEqual(options.TargetLanguageCodes.string, fake_options.TargetLanguageCodes.string,
+                         "Target languages should be equal!")
+        self.assertEqual(options.Deadline, fake_options.Deadline,
+                         "Deadlines should be equal!")
+        self.assertEqual(options.SourceLanguageCode, fake_options.SourceLanguageCode,
+                         "Source language codes should be equal!")
+        self.assertEqual(options.CreatorUser, fake_options.CreatorUser,
+                         "Creators should be equal!")
+
+    def test_create_project(self):
+        """ Test for create_project method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        test.delete()
+
+    def test_import_document(self):
+        """ Test for import_document method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        result = test.import_document(self.config["test_file_path"])
+        self.assertTrue(result, "Result should be true!")
+
+        test.delete()
+
+    def test_get_project_documents(self):
+        """ Test for get_project_documents method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        result = test.import_document(self.config["test_file_path"])
+        self.assertTrue(result, "Result should be true!")
+
+        filename = os.path.basename(self.config["test_file_path"])
+        test.get_project_documents()
+        self.assertEqual(test.documents[0][0].DocumentName,
+                         filename, "Name of document doesn't match test filename!")
+
+        test.delete()
+
+    def test_export_documents(self):
+        """ Test for export_documents method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        result = test.import_document(self.config["test_file_path"])
+        self.assertTrue(result, "Result should be true!")
+
+        filename = os.path.basename(self.config["test_file_path"])
+        test.get_project_documents()
+        self.assertEqual(test.documents[0][0].DocumentName,
+                         filename, "Name of document doesn't match test filename!")
+
+        export_result = test.export_documents(".")
+        self.assertTrue(export_result, "Export result should be true!")
+
+        test.delete()
+
+    def test_export_documents2(self):
+        """ Test for export_documents2 method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        result = test.import_document(self.config["test_file_path"])
+        self.assertTrue(result, "Result should be true!")
+
+        filename = os.path.basename(self.config["test_file_path"])
+        test.get_project_documents()
+        self.assertEqual(test.documents[0][0].DocumentName,
+                         filename, "Name of document doesn't match test filename!")
+
+        export_result = test.export_documents2(".")
+        self.assertTrue(export_result, "Export result should be true!")
+
+        test.delete()
+
+    def test_statistics_options(self):
+        """ Test for statistics_options method."""
+        test = memoQProject.MemoQProject()
+
+        fake_options = test.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}StatisticsOptions')
+        fake_options.Analysis_ProjectTMs = True
+        fake_options.Analysis_Homogenity = True
+        fake_options.ShowResultsPerFile = True
+        fake_options.RepetitionPreferenceOver100 = True
+        statistics_algorithm = test.client.factory.create(
+            '{http://schemas.datacontract.org/2004/07/MemoQServices}StatisticsAlgorithm')
+        fake_options.Algorithm.value = statistics_algorithm.MemoQ
+
+        options = test.statistics_options()
+        self.assertEqual(fake_options.Analysis_ProjectTMs, options.Analysis_ProjectTMs,
+                         "Project TMs option shouldn't be different!")
+        self.assertEqual(fake_options.Analysis_Homogenity, options.Analysis_Homogenity,
+                         "Analysis Homogenity option shouldn't be different!")
+        self.assertEqual(fake_options.Algorithm.value, options.Algorithm.value,
+                         "Algorithm value shouldn't be different!")
+
+    def test_run_statistics(self):
+        """ Test for run_statistics method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        result = test.import_document(self.config["test_file_path"])
+        self.assertTrue(result, "Result should be true!")
+
+        statistics = test.run_statistics()
+        self.assertNotEqual(statistics, None, "Statistics shouldn't be none!")
+
+        test.delete()
+
+    def test_save_statistics(self):
+        """ Test for save_statistics method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        result = test.import_document(self.config["test_file_path"])
+        self.assertTrue(result, "Result should be true!")
+
+        file_path = test.save_statistics(".")
+        self.assertTrue(os.path.isfile(file_path), "File should exist!")
+
+        os.remove(file_path)
+        test.delete()
+
+    def test_delete(self):
+        """ Test for delete method."""
+        test = memoQProject.MemoQProject()
+        test.project.languages.source = self.config["source_language"]
+        test.project.languages.target = self.config["target_languages"]
+
+        test.create_project()
+        self.assertNotEqual(test.project.get_project_guid(),
+                            None, "Guid shouldn't be none!")
+
+        guid = test.project.get_project_guid()
+
+        test.delete()
+        test.get_project_by_guid(guid)
+        self.assertNotEqual(test.project.get_project_guid(),
+                            guid, "Guids don't match!")
+
+
+if __name__ == "__main__":
+    unittest.main()

+ 73 - 0
memoQResource.py

@@ -0,0 +1,73 @@
+from suds.client import Client
+import memoQFile
+import json
+
+
+class MemoQResource(object):
+    """Client for memoQ Light Resource API."""
+
+    def __init__(self):
+        with open("config.json") as json_file:
+            self.config = json.load(json_file)
+
+        if self.config["api_base_url"] != "":
+            apiURL = self.config["api_base_url"] + \
+                "/memoqservices/resource?wsdl"
+            self.client = Client(apiURL)
+
+        self.types = self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}ResourceType')
+        self.guid = None
+        self.__type = None
+        self.info = None
+
+    def get_type(self):
+        """Returns resource type."""
+        return self.__type
+
+    def valid_type(self, value):
+        """Returns true if type is valid."""
+        if value in self.types:
+            return True
+        return False
+
+    def set_type(self, value):
+        """Sets resource type."""
+        if self.valid_type(value):
+            self.__type = self.types[value]
+
+    def __repr__(self):
+        if self.info != None:
+            return "{} - {} ({})".format(self.info.Name, self.info.Guid, self.get_type())
+        else:
+            return "No resource!"
+
+    def set_active_resource(self, guid=None, resource_type=None):
+        """Populates info basing on resource type and guid."""
+        if resource_type != None and guid != None:
+            self.set_type(resource_type)
+            self.guid = guid
+
+        if self.guid != None and self.get_type() != None:
+            self.info = self.client.service.GetResourceInfo(
+                self.get_type(), self.guid)
+
+    def get_resources_of_type(self, resource_type):
+        """Returns all resources of given type from memoQ server."""
+        if self.valid_type(resource_type):
+            return self.client.service.ListResources(resource_type)
+
+    def get_all_resources(self):
+        """Returns all resources from memoQ server."""
+        resources = []
+        for name, value in self.types:
+            for resource in self.get_resources_of_type(value):
+                resources.extend([(value, x) for x in resource[1]])
+        return resources
+
+    def download_resource(self, path):
+        """Downloads active resource to given path. Returns path to downloaded file."""
+        if self.get_type() != None and self.guid != None:
+            file_client = memoQFile.MemoQFile()
+            return file_client.download_file(
+                path, self.client.service.ExportResource(self.get_type(), self.guid))

+ 94 - 0
memoQResourceTest.py

@@ -0,0 +1,94 @@
+import unittest
+import memoQResource
+import json
+import os
+
+
+class MemoQResourceTest(unittest.TestCase):
+    """Tests for memoQResource module."""
+
+    def __init__(self, *args, **kwargs):
+        super(MemoQResourceTest, self).__init__(*args, **kwargs)
+        with open("testFiles/testConfig.json") as json_file:
+            self.config = json.load(json_file)
+
+    def test_valid_type(self):
+        """ Test for valid_type method."""
+        test = memoQResource.MemoQResource()
+
+        self.assertFalse(
+            test.valid_type(self.config["wrong_resource_type"]), "Wrong type should return false!")
+
+        self.assertTrue(
+            test.valid_type(self.config["valid_resource_type"]), "Valid type should return true!")
+
+    def test_set_type(self):
+        """ Test for set_type method."""
+        test = memoQResource.MemoQResource()
+
+        test.set_type(self.config["wrong_resource_type"])
+        self.assertEqual(
+            test.get_type(), None, "Setting wrong type succeeded!")
+
+        test.set_type(self.config["valid_resource_type"])
+        self.assertNotEqual(
+            test.get_type(), None, "Setting valid type failed!")
+
+    def test_set_active_resource(self):
+        """ Test for get_project_by_domain method."""
+        test = memoQResource.MemoQResource()
+
+        test.set_active_resource()
+        self.assertEqual(
+            test.info, None, "Setting active resource for empty object should return none!")
+
+        test.guid = self.config["valid_resource_guid"]
+        test.set_type(self.config["valid_resource_type"])
+        test.set_active_resource()
+        self.assertNotEqual(
+            test.info, None, "Setting active resource with valid guid \
+            and type shouldn't return none! (feilds)")
+
+        test = memoQResource.MemoQResource()
+        test.set_active_resource(self.config["valid_resource_guid"],
+                                 self.config["valid_resource_type"])
+        self.assertNotEqual(
+            test.info, None, "Setting active resource with valid guid \
+            and type shouldn't return none! (arguments)")
+
+    def test_get_resources_of_type(self):
+        """ Test for get_resources_of_type method."""
+        test = memoQResource.MemoQResource()
+
+        self.assertEqual(
+            test.get_resources_of_type(self.config["wrong_resource_type"]), None, "Lookup for wrong type should return none!")
+
+        self.assertNotEqual(test.get_resources_of_type(
+            self.config["valid_resource_type"]), None, "Lookup for valid type shouldn't return none!")
+
+    def test_get_all_resources(self):
+        """ Test for get_all_resources method."""
+        test = memoQResource.MemoQResource()
+        test.set_active_resource(self.config["valid_resource_guid"],
+                                 self.config["valid_resource_type"])
+
+        resources = test.get_all_resources()
+        self.assertTrue(len(resources),
+                        "List of resources shouldn't be empty!")
+
+        self.assertTrue(len([x for x in resources if x[1].Guid == test.info.Guid and x[1].Name == test.info.Name]),
+                        "List should contain our valid resource!")
+
+    def test_download_resource(self):
+        """ Test for download_resource method."""
+        test = memoQResource.MemoQResource()
+        test.set_active_resource(self.config["valid_resource_guid"],
+                                 self.config["valid_resource_type"])
+
+        file_path = test.download_resource(".")
+        self.assertTrue(os.path.isfile(file_path), "File should exist!")
+
+        os.remove(file_path)
+
+if __name__ == "__main__":
+    unittest.main()

+ 194 - 0
memoQSecurity.py

@@ -0,0 +1,194 @@
+from suds.client import Client
+import hashlib
+import json
+
+
+class Group(object):
+    """Wrapper for group."""
+
+    def __init__(self, group_info=None):
+        self.info = group_info
+
+    def __repr__(self):
+        if self.info != None:
+            return "{} - {}".format(self.info.GroupName, self.info.GroupGuid)
+        else:
+            return "No group!"
+
+
+class User(object):
+    """Wrapper for user."""
+
+    def __init__(self, user_info=None):
+        self.info = user_info
+
+    def valid_user_info(self):
+        """ Returns true if given user_info has all required attributes."""
+        required_attributes = ["EmailAddress", "FullName",
+                               "Password", "UserName", "PackageWorkflowType", "UserGuid"]
+
+        for attribute in required_attributes:
+            if not hasattr(self.info, attribute):
+                return False
+            return True
+
+    def __repr__(self):
+        if self.info != None:
+            return "{} - {}".format(self.info.FullName, self.info.UserGuid)
+        else:
+            return "No user!"
+
+
+class MemoQSecurity(object):
+    """Client for memoQ Security API."""
+
+    def __init__(self):
+        with open("config.json") as json_file:
+            self.config = json.load(json_file)
+
+        if self.config["api_base_url"] != "":
+            apiURL = self.config["api_base_url"] + \
+                "/memoqservices/security?wsdl"
+            self.client = Client(apiURL)
+
+        self.user = None
+        self.users = []
+        self.groups = None
+        self.subvendors = None
+
+    def set_active_user(self, guid):
+        """Sets user of given guid as active."""
+        self.user = User(self.client.service.GetUser(guid))
+
+    def get_users(self):
+        """Gets list of users from the server into users field."""
+        self.users = [User(x) for x in self.client.service.ListUsers()[0]]
+
+    def user_by_name(self, username):
+        """ Returns list of users of given fullname (can be partial) from users field."""
+        if not len(self.users):
+            self.get_users()
+
+        return [x for x in self.users if username in x.info.FullName]
+
+    def not_empty_user_info(self):
+        """Validates user info of active user. Returns true on success."""
+        if self.user.valid_user_info():
+            if self.user.info.EmailAddress != None \
+                    and self.user.info.FullName != None \
+                    and self.user.info.Password != None \
+                    and self.user.info.UserName != None \
+                    and self.user.info.PackageWorkflowType != None:
+                return True
+        return False
+
+    def set_password(self, password):
+        """Hashes and sets password for active user."""
+        if self.user.info != None and password != "":
+            salt = 'fgad s d f sgds g  sdg gfdg'
+            to_hash = (password + salt).encode('utf-8')
+            self.user.info.Password = str(
+                hashlib.sha1(to_hash).hexdigest()).upper()
+
+    def new_user(self):
+        """ Sets empty user info as active user (package workflow = online).
+        For further user creation."""
+        self.user = User(self.client.factory.create(
+            '{http://kilgray.com/memoqservices/2007}UserInfo'))
+        package_workflow = self.client.factory.create(
+            '{http://schemas.datacontract.org/2004/07/MemoQServices}UserPackageWorkflowType')
+        self.user.info.PackageWorkflowType.value = package_workflow.Online
+
+    def create_user(self):
+        """ Creates new user on server from active user. Returns guid."""
+        if self.not_empty_user_info():
+            guid = self.client.service.CreateUser(self.user.info)
+            if guid != None:
+                self.set_active_user(guid)
+            return guid
+
+    def update_user(self):
+        """ Updates user info on server. Returns true on success."""
+        if self.not_empty_user_info():
+            self.client.service.UpdateUser(self.user.info)
+            return True
+        return False
+
+    def delete_user(self):
+        """ Deletes active user. Dangerous! Returns true on success."""
+        if self.user != None and self.user.valid_user_info() and self.user.info.UserGuid != None:
+            self.client.service.DeleteUser(self.user.info.UserGuid)
+            return True
+        return False
+
+    def get_groups(self):
+        """ Gets list of groups from the server into groups field."""
+        self.groups = [Group(x) for x in self.client.service.ListGroups()[0]]
+
+    def group_by_name(self, groupname):
+        """ Returns list of groups of given group name (can be partial) from groups field."""
+        if self.groups == None:
+            self.get_groups()
+
+        return [x for x in self.groups if groupname in x.info.GroupName]
+
+    def get_subvendors(self):
+        """ Gets list of subvendor groups from the server into subvendors field."""
+        self.subvendors = [
+            Group(x) for x in self.client.service.ListSubvendorGroups()[0]]
+
+    def subvendor_by_name(self, groupname):
+        """ Returns list of subvendor groups of given group name (can be partial) from subvendors field."""
+        if self.subvendors == None:
+            self.get_subvendors()
+
+        return [x for x in self.subvendors if groupname in x.info.GroupName]
+
+    def users_of_group(self, guid):
+        """Returns list of users of group of given guid."""
+        if guid == None:
+            return []
+
+        try:
+            users = [User(x)
+                     for x in self.client.service.ListUsersOfGroup(guid)[0]]
+            return users
+        except:
+            return []
+
+    def add_current_user_to_group(self, group_guid):
+        """Adds current user to group of given guid. Returns true on success."""
+        if self.user != None and self.user.valid_user_info() and group_guid != None:
+            group_users = self.users_of_group(group_guid)
+            if len(group_users):
+                new_users_guids = self.client.factory.create(
+                    '{http://kilgray.com/memoqservices/2007}userGuids')
+                new_users_guids.guid = [
+                    user.info.UserGuid for user in group_users]
+                new_users_guids.guid.append(self.user.info.UserGuid)
+                if len(new_users_guids):
+                    try:
+                        self.client.service.SetUsersOfGroup(
+                            group_guid, new_users_guids)
+                        return True
+                    except:
+                        return False
+        return False
+
+    def remove_current_user_from_group(self, group_guid):
+        """Removes current user from group of given guid. Returns true on success."""
+        if self.user != None and self.user.valid_user_info() and group_guid != None:
+            group_users = self.users_of_group(group_guid)
+            if len(group_users) and len([x for x in group_users if x.info.UserGuid == self.user.info.UserGuid]):
+                new_users_guids = self.client.factory.create(
+                    '{http://kilgray.com/memoqservices/2007}userGuids')
+                new_users_guids.guid = [
+                    user.info.UserGuid for user in group_users if user.info.UserGuid != self.user.info.UserGuid]
+                if len(new_users_guids):
+                    try:
+                        self.client.service.SetUsersOfGroup(
+                            group_guid, new_users_guids)
+                        return True
+                    except:
+                        return False
+        return False

+ 194 - 0
memoQSecurityTest.py

@@ -0,0 +1,194 @@
+import unittest
+import memoQSecurity
+import json
+import os
+
+
+class MemoQSecurityTest(unittest.TestCase):
+    """Tests for memoQSecurity module."""
+
+    def __init__(self, *args, **kwargs):
+        super(MemoQSecurityTest, self).__init__(*args, **kwargs)
+        with open("testFiles/testConfig.json") as json_file:
+            self.config = json.load(json_file)
+
+    def test_set_active_user(self):
+        """Test for set_active_user method."""
+        test = memoQSecurity.MemoQSecurity()
+
+        test.set_active_user(self.config["wrong_user_guid"])
+        self.assertFalse(test.user.valid_user_info(),
+                         "User info shouldn't be valid for wrong guid!")
+
+        test.set_active_user(self.config["valid_user_guid"])
+        self.assertTrue(test.user.valid_user_info(),
+                        "User info should be valid for valid guid!")
+        self.assertEqual(test.user.info.FullName,
+                         self.config["valid_user_name"], "Names should match!")
+
+    def test_get_users(self):
+        """Test for get_users method."""
+        test = memoQSecurity.MemoQSecurity()
+
+        test.get_users()
+
+        self.assertTrue(len(test.users), "List of users shouldn't be empty!")
+
+    def test_user_by_name(self):
+        """Test for user_by_name method."""
+        test = memoQSecurity.MemoQSecurity()
+
+        self.assertFalse(len(test.user_by_name(
+            self.config["wrong_user_name"])), "List of users for wrong username should be empty!")
+
+        self.assertTrue(len(test.user_by_name(
+            self.config["valid_user_name"])), "List of users for valid username shouldn't be empty!")
+
+    def test_set_password(self):
+        """Test for set_password method."""
+        test = memoQSecurity.MemoQSecurity()
+        test.set_active_user(self.config["valid_user_guid"])
+
+        password = test.user.info.Password
+
+        test.set_password("")
+        self.assertEqual(test.user.info.Password, password,
+                         "Password shouldn't be changed to empty!")
+
+        test.set_password("something")
+        self.assertNotEqual(test.user.info.Password, password,
+                            "Password should be changed!")
+
+    def test_new_user(self):
+        """Test for new_user method."""
+        test = memoQSecurity.MemoQSecurity()
+        test.new_user()
+
+        self.assertNotEqual(test.user, None, "User shouldn't be none!")
+
+        self.assertTrue(test.user.valid_user_info(),
+                        "User info should be valid!")
+
+        self.assertEqual(test.user.info.PackageWorkflowType.value,
+                         "Online", "Package workflow should be set to online!")
+
+    def test_create_update_delete_user(self):
+        """Test for create_user, update_user and delete_user methods."""
+        test = memoQSecurity.MemoQSecurity()
+
+        # Create new user
+        test.new_user()
+        test.user.info.EmailAddress = "anon@anon.com"
+        test.user.info.FullName = "Anonymous Mouse"
+        test.set_password("something123")
+        test.user.info.UserName = "anonymous"
+
+        guid = test.create_user()
+        self.assertNotEqual(guid, None, "Guid shouldn't be none!")
+
+        # Update user
+        new_fullname = "Anonymous Mouse2"
+        test.user.info.FullName = new_fullname
+        self.assertFalse(test.update_user(),
+                         "Update should return false for password not set!")
+
+        test.set_password("something123")
+        self.assertTrue(test.update_user(), "Update should return true!")
+
+        test.set_active_user(guid)
+        self.assertEqual(test.user.info.FullName,
+                         new_fullname, "Names should be equal!")
+
+        # Delete user
+        test = memoQSecurity.MemoQSecurity()
+        self.assertFalse(test.delete_user(),
+                         "Deletion should fail for no user!")
+
+        test.set_active_user(guid)
+        self.assertTrue(test.delete_user(), "Deletion should succeed!")
+
+        test.set_active_user(guid)
+        self.assertFalse(test.user.valid_user_info(),
+                         "User info shouldn't be valid for deleted user!")
+
+    def test_get_groups(self):
+        """Test for get_groups method."""
+        test = memoQSecurity.MemoQSecurity()
+
+        test.get_groups()
+
+        self.assertTrue(len(test.groups), "List of groups shouldn't be empty!")
+
+    def test_group_by_name(self):
+        """Test for group_by_name method."""
+        test = memoQSecurity.MemoQSecurity()
+
+        self.assertFalse(len(test.group_by_name(
+            self.config["wrong_group_name"])), "List of groups for wrong group name should be empty!")
+
+        self.assertTrue(len(test.group_by_name(
+            self.config["valid_group_name"])), "List of groups for valid group name shouldn't be empty!")
+
+    def test_get_subvendors(self):
+        """Test for get_subvendors method."""
+        test = memoQSecurity.MemoQSecurity()
+
+        test.get_subvendors()
+
+        self.assertTrue(len(test.subvendors),
+                        "List of subvendors shouldn't be empty!")
+
+    def test_users_of_group(self):
+        """Test for users_of_group method."""
+        test = memoQSecurity.MemoQSecurity()
+
+        self.assertFalse(len(test.users_of_group(self.config[
+                         "wrong_group_guid"])), "List of users should be empty for wrong guid!")
+
+        self.assertFalse(len(test.users_of_group(None)),
+                         "List of users should be empty for no guid!")
+
+        self.assertTrue(len(test.users_of_group(self.config[
+                        "valid_group_guid"])), "List of users shouldn't be empty for valid guid!")
+
+    def test_add_remove_current_user_tofrom_group(self):
+        """Test for add_current_user_to_group and remove_current_user_from_group methods."""
+        test = memoQSecurity.MemoQSecurity()
+
+        test.set_active_user(self.config["wrong_user_guid"])
+        self.assertFalse(test.add_current_user_to_group(self.config["valid_group_guid"]),
+                         "Should be false if wrong user but valid group guid! (adding)")
+        self.assertFalse(test.remove_current_user_from_group(self.config["valid_group_guid"]),
+                         "Should be false if wrong user but valid group guid! (deleting)")
+
+        test.set_active_user(self.config["valid_user_guid"])
+        self.assertFalse(test.add_current_user_to_group(self.config[
+                         "wrong_group_guid"]),
+                         "Should be false if valid user but wrong group guid! (adding)")
+        self.assertFalse(test.remove_current_user_from_group(self.config[
+                         "wrong_group_guid"]),
+                         "Should be false if valid user but wrong group guid! (deleting)")
+
+        # Adding valid user to valid group
+        self.assertTrue(test.add_current_user_to_group(self.config["valid_group_guid"]),
+                        "Should be true if valid user and group guid! (adding)")
+
+        users = test.users_of_group(self.config[
+            "valid_group_guid"])
+        self.assertTrue(len([x for x in users if x.info.UserGuid ==
+                             self.config[
+                                 "valid_user_guid"]]),
+                        "Valid user should be part of the group after adding!")
+
+        # Removing valid user from valid group
+        self.assertTrue(test.remove_current_user_from_group(self.config["valid_group_guid"]),
+                        "Should be true if valid user and group guid! (deleting)")
+
+        users = test.users_of_group(self.config[
+            "valid_group_guid"])
+        self.assertFalse(len([x for x in users if x.info.UserGuid ==
+                              self.config["valid_user_guid"]]),
+                         "Valid user shouldn't be part of the group after deleting!")
+
+if __name__ == "__main__":
+    unittest.main()

+ 74 - 0
memoQTM.py

@@ -0,0 +1,74 @@
+from suds.client import Client
+from base64 import b64decode, b64encode
+import os
+import json
+
+
+class MemoQTM(object):
+    """Client for memoQ Translation memory API."""
+
+    def __init__(self):
+        with open("config.json") as json_file:
+            self.config = json.load(json_file)
+
+        if self.config["api_base_url"] != "":
+            apiURL = self.config["api_base_url"] + "/memoqservices/tm?wsdl"
+            self.client = Client(apiURL)
+
+        self.__guid = None
+        self.info = None
+
+    def get_guid(self):
+        """Returns guid of active TM."""
+        return self.__guid
+
+    def get_tm_details(self, guid):
+        """Returns TM Info for TM of given guid or none if no TM or connection problems."""
+        try:
+            info = self.client.service.GetTMInfo(guid)
+            return info
+        except:
+            return None
+
+    def set_active_tm(self, guid):
+        """Sets guid and info if TM exists."""
+        tm_info = self.get_tm_details(guid)
+        if tm_info != None:
+            self.__guid = guid
+            self.info = tm_info
+
+    def __repr__(self):
+        if self.info != None:
+            return "{} - {}\n{} - {}".format(self.info.Name, self.info.Guid, self.info.SourceLanguageCode, self.info.TargetLanguageCode)
+        else:
+            return "No TM!"
+
+    def all_tms(self):
+        return self.client.service.ListTMs()
+
+    def download_tmx(self, path, guid=None):
+        """Downloads TMX export of active or given TM to given path. Returns path to TMX file or none on any failure."""
+        if guid != None:
+            self.set_active_tm(guid)
+        if self.info == None:
+            return None
+
+        session_id = self.client.service.BeginChunkedTMXExport(self.get_guid())
+        output_filename = os.path.join(path, (self.info.Name + ".tmx"))
+        output = open(output_filename, 'wb')
+        while True:
+            try:
+                chunk = self.client.service.GetNextTMXChunk(session_id)
+                if chunk is not None:
+                    output.write(b64decode(chunk))
+                else:
+                    break
+            except:
+                self.client.service.EndChunkedTMXExport(session_id)
+                output.close()
+                return None
+
+        output.close()
+        self.client.service.EndChunkedTMXExport(session_id)
+
+        return output_filename

+ 72 - 0
memoQTMTest.py

@@ -0,0 +1,72 @@
+import unittest
+import memoQTM
+import json
+import os
+
+
+class MemoQTMTest(unittest.TestCase):
+    """Tests for memoQTM module."""
+
+    def __init__(self, *args, **kwargs):
+        super(MemoQTMTest, self).__init__(*args, **kwargs)
+        with open("testFiles/testConfig.json") as json_file:
+            self.config = json.load(json_file)
+
+    def test_get_tm_details(self):
+        """Test for get_tm_details method."""
+        test = memoQTM.MemoQTM()
+
+        self.assertEqual(
+            test.get_tm_details(self.config["wrong_tm_guid"]), None,
+            "TM Info for wrong TM guid should be none!")
+
+        self.assertNotEqual(
+            test.get_tm_details(self.config["valid_tm_guid"]), None,
+            "TM Info for wrong TM guid shouldn't be none!")
+
+    def test_set_active_tm(self):
+        """Test for set_active_tm method."""
+        test = memoQTM.MemoQTM()
+
+        test.set_active_tm(self.config["wrong_tm_guid"])
+        self.assertEqual(
+            test.info, None, "TM Info for wrong TM guid should be none!")
+
+        test.set_active_tm(self.config["valid_tm_guid"])
+        self.assertNotEqual(
+            test.info, None, "TM Info for valid TM guid shouldn't be none!")
+
+    def test_all_tms(self):
+        """Test for all_tms method."""
+        test = memoQTM.MemoQTM()
+        self.assertTrue(len(test.all_tms()), "List of TMs shouldn't be empty!")
+
+    def test_download_tmx(self):
+        """Test for download_tmx method."""
+        test = memoQTM.MemoQTM()
+
+        file_path = test.download_tmx(".", self.config["wrong_tm_guid"])
+        self.assertEqual(file_path, None,
+                         "Filepath for wrong guid should be none!")
+
+        file_path = test.download_tmx(".", self.config["valid_tm_guid"])
+        self.assertNotEqual(file_path, None,
+                            "Filepath shouldn't be none! (argument)")
+        self.assertTrue(os.path.isfile(file_path),
+                        "File should exist! (argument)")
+        os.remove(file_path)
+
+        test = memoQTM.MemoQTM()
+        test.set_active_tm(self.config["valid_tm_guid"])
+        self.assertNotEqual(
+            test.info, None, "TM Info for valid TM guid shouldn't be none!")
+
+        file_path = test.download_tmx(".")
+        self.assertNotEqual(file_path, None,
+                            "Filepath shouldn't be none! (field)")
+        self.assertTrue(os.path.isfile(file_path),
+                        "File should exist! (field)")
+        os.remove(file_path)
+
+if __name__ == "__main__":
+    unittest.main()

+ 1 - 0
testFiles/test.txt

@@ -0,0 +1 @@
+Lorem ipsum dolor.

+ 23 - 0
testFiles/testConfig.json

@@ -0,0 +1,23 @@
+{
+    "source_language" : "eng",
+    "target_languages" : ["ger-DE"],
+    "valid_domain" : "Python",
+    "wrong_domain" : "dsfdsfdsfew",
+    "project_template_guid" : "6ec5df0f-4dc4-4f91-b6b4-c7927cc4dfd3",
+    "creator_guid" : "00000000-0000-0000-0001-000000000001",
+    "test_file_path" : "testFiles/test.txt",
+    "valid_resource_guid" : "6ec5df0f-4dc4-4f91-b6b4-c7927cc4dfd3",
+    "valid_resource_type" : "ProjectTemplate",
+    "wrong_resource_guid" : "00000000-0000-0000-0001-000000000001",
+    "wrong_resource_type" : "dsfdsfdsfew",
+    "valid_tm_guid" : "5b83261b-333c-4994-a358-796dcc83410c",
+    "wrong_tm_guid" : "00000000-0000-0000-0001-000000000001",
+    "valid_user_name" : "Administrator",
+    "wrong_user_name" : "kjdshfhesdhfkhd",
+    "valid_user_guid" : "00000000-0000-0000-0001-000000000001",
+    "wrong_user_guid" : "6ec5df0f-4dc4-4f91-b6b4-c7927cc4dfd3",
+    "valid_group_name" : "Administrators",
+    "wrong_group_name" : "kjdshfhesdhfkhd",
+    "valid_group_guid" : "00000000-0000-0000-0000-000000000002",
+    "wrong_group_guid" : "6ec5df0f-4dc4-4f91-b6b4-c7927cc4dfd3"
+}