1. import os
    
  2. import re
    
  3. import shutil
    
  4. import tempfile
    
  5. 
    
  6. source_code_dir = os.path.dirname(__file__)
    
  7. 
    
  8. 
    
  9. def copytree(src, dst):
    
  10.     shutil.copytree(src, dst, ignore=shutil.ignore_patterns("__pycache__"))
    
  11. 
    
  12. 
    
  13. class POFileAssertionMixin:
    
  14.     def _assertPoKeyword(self, keyword, expected_value, haystack, use_quotes=True):
    
  15.         q = '"'
    
  16.         if use_quotes:
    
  17.             expected_value = '"%s"' % expected_value
    
  18.             q = "'"
    
  19.         needle = "%s %s" % (keyword, expected_value)
    
  20.         expected_value = re.escape(expected_value)
    
  21.         return self.assertTrue(
    
  22.             re.search("^%s %s" % (keyword, expected_value), haystack, re.MULTILINE),
    
  23.             "Could not find %(q)s%(n)s%(q)s in generated PO file"
    
  24.             % {"n": needle, "q": q},
    
  25.         )
    
  26. 
    
  27.     def assertMsgId(self, msgid, haystack, use_quotes=True):
    
  28.         return self._assertPoKeyword("msgid", msgid, haystack, use_quotes=use_quotes)
    
  29. 
    
  30. 
    
  31. class RunInTmpDirMixin:
    
  32.     """
    
  33.     Allow i18n tests that need to generate .po/.mo files to run in an isolated
    
  34.     temporary filesystem tree created by tempfile.mkdtemp() that contains a
    
  35.     clean copy of the relevant test code.
    
  36. 
    
  37.     Test classes using this mixin need to define a `work_subdir` attribute
    
  38.     which designates the subdir under `tests/i18n/` that will be copied to the
    
  39.     temporary tree from which its test cases will run.
    
  40. 
    
  41.     The setUp() method sets the current working dir to the temporary tree.
    
  42.     It'll be removed when cleaning up.
    
  43.     """
    
  44. 
    
  45.     def setUp(self):
    
  46.         self._cwd = os.getcwd()
    
  47.         self.work_dir = tempfile.mkdtemp(prefix="i18n_")
    
  48.         # Resolve symlinks, if any, in test directory paths.
    
  49.         self.test_dir = os.path.realpath(os.path.join(self.work_dir, self.work_subdir))
    
  50.         copytree(os.path.join(source_code_dir, self.work_subdir), self.test_dir)
    
  51.         # Step out of the temporary working tree before removing it to avoid
    
  52.         # deletion problems on Windows. Cleanup actions registered with
    
  53.         # addCleanup() are called in reverse so preserve this ordering.
    
  54.         self.addCleanup(self._rmrf, self.test_dir)
    
  55.         self.addCleanup(os.chdir, self._cwd)
    
  56.         os.chdir(self.test_dir)
    
  57. 
    
  58.     def _rmrf(self, dname):
    
  59.         if (
    
  60.             os.path.commonprefix([self.test_dir, os.path.abspath(dname)])
    
  61.             != self.test_dir
    
  62.         ):
    
  63.             return
    
  64.         shutil.rmtree(dname)