fixtures.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. from __future__ import unicode_literals
  2. import os
  3. import sys
  4. import shutil
  5. import tempfile
  6. import textwrap
  7. import contextlib
  8. try:
  9. from contextlib import ExitStack
  10. except ImportError:
  11. from contextlib2 import ExitStack
  12. try:
  13. import pathlib
  14. except ImportError:
  15. import pathlib2 as pathlib
  16. __metaclass__ = type
  17. @contextlib.contextmanager
  18. def tempdir():
  19. tmpdir = tempfile.mkdtemp()
  20. try:
  21. yield pathlib.Path(tmpdir)
  22. finally:
  23. shutil.rmtree(tmpdir)
  24. @contextlib.contextmanager
  25. def save_cwd():
  26. orig = os.getcwd()
  27. try:
  28. yield
  29. finally:
  30. os.chdir(orig)
  31. @contextlib.contextmanager
  32. def tempdir_as_cwd():
  33. with tempdir() as tmp:
  34. with save_cwd():
  35. os.chdir(str(tmp))
  36. yield tmp
  37. class SiteDir:
  38. def setUp(self):
  39. self.fixtures = ExitStack()
  40. self.addCleanup(self.fixtures.close)
  41. self.site_dir = self.fixtures.enter_context(tempdir())
  42. class OnSysPath:
  43. @staticmethod
  44. @contextlib.contextmanager
  45. def add_sys_path(dir):
  46. sys.path[:0] = [str(dir)]
  47. try:
  48. yield
  49. finally:
  50. sys.path.remove(str(dir))
  51. def setUp(self):
  52. super(OnSysPath, self).setUp()
  53. self.fixtures.enter_context(self.add_sys_path(self.site_dir))
  54. class DistInfoPkg(OnSysPath, SiteDir):
  55. files = {
  56. "distinfo_pkg-1.0.0.dist-info": {
  57. "METADATA": """
  58. Name: distinfo-pkg
  59. Author: Steven Ma
  60. Version: 1.0.0
  61. Requires-Dist: wheel >= 1.0
  62. Requires-Dist: pytest; extra == 'test'
  63. """,
  64. "RECORD": "mod.py,sha256=abc,20\n",
  65. "entry_points.txt": """
  66. [entries]
  67. main = mod:main
  68. """
  69. },
  70. "mod.py": """
  71. def main():
  72. print("hello world")
  73. """,
  74. }
  75. def setUp(self):
  76. super(DistInfoPkg, self).setUp()
  77. build_files(DistInfoPkg.files, self.site_dir)
  78. class DistInfoPkgOffPath(SiteDir):
  79. def setUp(self):
  80. super(DistInfoPkgOffPath, self).setUp()
  81. build_files(DistInfoPkg.files, self.site_dir)
  82. class EggInfoPkg(OnSysPath, SiteDir):
  83. files = {
  84. "egginfo_pkg.egg-info": {
  85. "PKG-INFO": """
  86. Name: egginfo-pkg
  87. Author: Steven Ma
  88. License: Unknown
  89. Version: 1.0.0
  90. Classifier: Intended Audience :: Developers
  91. Classifier: Topic :: Software Development :: Libraries
  92. """,
  93. "SOURCES.txt": """
  94. mod.py
  95. egginfo_pkg.egg-info/top_level.txt
  96. """,
  97. "entry_points.txt": """
  98. [entries]
  99. main = mod:main
  100. """,
  101. "requires.txt": """
  102. wheel >= 1.0; python_version >= "2.7"
  103. [test]
  104. pytest
  105. """,
  106. "top_level.txt": "mod\n"
  107. },
  108. "mod.py": """
  109. def main():
  110. print("hello world")
  111. """,
  112. }
  113. def setUp(self):
  114. super(EggInfoPkg, self).setUp()
  115. build_files(EggInfoPkg.files, prefix=self.site_dir)
  116. class EggInfoFile(OnSysPath, SiteDir):
  117. files = {
  118. "egginfo_file.egg-info": """
  119. Metadata-Version: 1.0
  120. Name: egginfo_file
  121. Version: 0.1
  122. Summary: An example package
  123. Home-page: www.example.com
  124. Author: Eric Haffa-Vee
  125. Author-email: eric@example.coms
  126. License: UNKNOWN
  127. Description: UNKNOWN
  128. Platform: UNKNOWN
  129. """,
  130. }
  131. def setUp(self):
  132. super(EggInfoFile, self).setUp()
  133. build_files(EggInfoFile.files, prefix=self.site_dir)
  134. def build_files(file_defs, prefix=pathlib.Path()):
  135. """Build a set of files/directories, as described by the
  136. file_defs dictionary. Each key/value pair in the dictionary is
  137. interpreted as a filename/contents pair. If the contents value is a
  138. dictionary, a directory is created, and the dictionary interpreted
  139. as the files within it, recursively.
  140. For example:
  141. {"README.txt": "A README file",
  142. "foo": {
  143. "__init__.py": "",
  144. "bar": {
  145. "__init__.py": "",
  146. },
  147. "baz.py": "# Some code",
  148. }
  149. }
  150. """
  151. for name, contents in file_defs.items():
  152. full_name = prefix / name
  153. if isinstance(contents, dict):
  154. full_name.mkdir()
  155. build_files(contents, prefix=full_name)
  156. else:
  157. if isinstance(contents, bytes):
  158. with full_name.open('wb') as f:
  159. f.write(contents)
  160. else:
  161. with full_name.open('w') as f:
  162. f.write(DALS(contents))
  163. def DALS(str):
  164. "Dedent and left-strip"
  165. return textwrap.dedent(str).lstrip()