python (3.12.0)

(root)/
lib/
python3.12/
test/
test_importlib/
fixtures.py
       1  import os
       2  import sys
       3  import copy
       4  import shutil
       5  import pathlib
       6  import tempfile
       7  import textwrap
       8  import functools
       9  import contextlib
      10  
      11  from test.support.os_helper import FS_NONASCII
      12  from test.support import requires_zlib
      13  
      14  from . import _path
      15  from ._path import FilesSpec
      16  
      17  
      18  try:
      19      from importlib import resources  # type: ignore
      20  
      21      getattr(resources, 'files')
      22      getattr(resources, 'as_file')
      23  except (ImportError, AttributeError):
      24      import importlib_resources as resources  # type: ignore
      25  
      26  
      27  @contextlib.contextmanager
      28  def tempdir():
      29      tmpdir = tempfile.mkdtemp()
      30      try:
      31          yield pathlib.Path(tmpdir)
      32      finally:
      33          shutil.rmtree(tmpdir)
      34  
      35  
      36  @contextlib.contextmanager
      37  def save_cwd():
      38      orig = os.getcwd()
      39      try:
      40          yield
      41      finally:
      42          os.chdir(orig)
      43  
      44  
      45  @contextlib.contextmanager
      46  def tempdir_as_cwd():
      47      with tempdir() as tmp:
      48          with save_cwd():
      49              os.chdir(str(tmp))
      50              yield tmp
      51  
      52  
      53  @contextlib.contextmanager
      54  def install_finder(finder):
      55      sys.meta_path.append(finder)
      56      try:
      57          yield
      58      finally:
      59          sys.meta_path.remove(finder)
      60  
      61  
      62  class ESC[4;38;5;81mFixtures:
      63      def setUp(self):
      64          self.fixtures = contextlib.ExitStack()
      65          self.addCleanup(self.fixtures.close)
      66  
      67  
      68  class ESC[4;38;5;81mSiteDir(ESC[4;38;5;149mFixtures):
      69      def setUp(self):
      70          super().setUp()
      71          self.site_dir = self.fixtures.enter_context(tempdir())
      72  
      73  
      74  class ESC[4;38;5;81mOnSysPath(ESC[4;38;5;149mFixtures):
      75      @staticmethod
      76      @contextlib.contextmanager
      77      def add_sys_path(dir):
      78          sys.path[:0] = [str(dir)]
      79          try:
      80              yield
      81          finally:
      82              sys.path.remove(str(dir))
      83  
      84      def setUp(self):
      85          super().setUp()
      86          self.fixtures.enter_context(self.add_sys_path(self.site_dir))
      87  
      88  
      89  class ESC[4;38;5;81mDistInfoPkg(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
      90      files: FilesSpec = {
      91          "distinfo_pkg-1.0.0.dist-info": {
      92              "METADATA": """
      93                  Name: distinfo-pkg
      94                  Author: Steven Ma
      95                  Version: 1.0.0
      96                  Requires-Dist: wheel >= 1.0
      97                  Requires-Dist: pytest; extra == 'test'
      98                  Keywords: sample package
      99  
     100                  Once upon a time
     101                  There was a distinfo pkg
     102                  """,
     103              "RECORD": "mod.py,sha256=abc,20\n",
     104              "entry_points.txt": """
     105                  [entries]
     106                  main = mod:main
     107                  ns:sub = mod:main
     108              """,
     109          },
     110          "mod.py": """
     111              def main():
     112                  print("hello world")
     113              """,
     114      }
     115  
     116      def setUp(self):
     117          super().setUp()
     118          build_files(DistInfoPkg.files, self.site_dir)
     119  
     120      def make_uppercase(self):
     121          """
     122          Rewrite metadata with everything uppercase.
     123          """
     124          shutil.rmtree(self.site_dir / "distinfo_pkg-1.0.0.dist-info")
     125          files = copy.deepcopy(DistInfoPkg.files)
     126          info = files["distinfo_pkg-1.0.0.dist-info"]
     127          info["METADATA"] = info["METADATA"].upper()
     128          build_files(files, self.site_dir)
     129  
     130  
     131  class ESC[4;38;5;81mDistInfoPkgWithDot(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
     132      files: FilesSpec = {
     133          "pkg_dot-1.0.0.dist-info": {
     134              "METADATA": """
     135                  Name: pkg.dot
     136                  Version: 1.0.0
     137                  """,
     138          },
     139      }
     140  
     141      def setUp(self):
     142          super().setUp()
     143          build_files(DistInfoPkgWithDot.files, self.site_dir)
     144  
     145  
     146  class ESC[4;38;5;81mDistInfoPkgWithDotLegacy(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
     147      files: FilesSpec = {
     148          "pkg.dot-1.0.0.dist-info": {
     149              "METADATA": """
     150                  Name: pkg.dot
     151                  Version: 1.0.0
     152                  """,
     153          },
     154          "pkg.lot.egg-info": {
     155              "METADATA": """
     156                  Name: pkg.lot
     157                  Version: 1.0.0
     158                  """,
     159          },
     160      }
     161  
     162      def setUp(self):
     163          super().setUp()
     164          build_files(DistInfoPkgWithDotLegacy.files, self.site_dir)
     165  
     166  
     167  class ESC[4;38;5;81mDistInfoPkgOffPath(ESC[4;38;5;149mSiteDir):
     168      def setUp(self):
     169          super().setUp()
     170          build_files(DistInfoPkg.files, self.site_dir)
     171  
     172  
     173  class ESC[4;38;5;81mEggInfoPkg(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
     174      files: FilesSpec = {
     175          "egginfo_pkg.egg-info": {
     176              "PKG-INFO": """
     177                  Name: egginfo-pkg
     178                  Author: Steven Ma
     179                  License: Unknown
     180                  Version: 1.0.0
     181                  Classifier: Intended Audience :: Developers
     182                  Classifier: Topic :: Software Development :: Libraries
     183                  Keywords: sample package
     184                  Description: Once upon a time
     185                          There was an egginfo package
     186                  """,
     187              "SOURCES.txt": """
     188                  mod.py
     189                  egginfo_pkg.egg-info/top_level.txt
     190              """,
     191              "entry_points.txt": """
     192                  [entries]
     193                  main = mod:main
     194              """,
     195              "requires.txt": """
     196                  wheel >= 1.0; python_version >= "2.7"
     197                  [test]
     198                  pytest
     199              """,
     200              "top_level.txt": "mod\n",
     201          },
     202          "mod.py": """
     203              def main():
     204                  print("hello world")
     205              """,
     206      }
     207  
     208      def setUp(self):
     209          super().setUp()
     210          build_files(EggInfoPkg.files, prefix=self.site_dir)
     211  
     212  
     213  class ESC[4;38;5;81mEggInfoPkgPipInstalledNoToplevel(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
     214      files: FilesSpec = {
     215          "egg_with_module_pkg.egg-info": {
     216              "PKG-INFO": "Name: egg_with_module-pkg",
     217              # SOURCES.txt is made from the source archive, and contains files
     218              # (setup.py) that are not present after installation.
     219              "SOURCES.txt": """
     220                  egg_with_module.py
     221                  setup.py
     222                  egg_with_module_pkg.egg-info/PKG-INFO
     223                  egg_with_module_pkg.egg-info/SOURCES.txt
     224                  egg_with_module_pkg.egg-info/top_level.txt
     225              """,
     226              # installed-files.txt is written by pip, and is a strictly more
     227              # accurate source than SOURCES.txt as to the installed contents of
     228              # the package.
     229              "installed-files.txt": """
     230                  ../egg_with_module.py
     231                  PKG-INFO
     232                  SOURCES.txt
     233                  top_level.txt
     234              """,
     235              # missing top_level.txt (to trigger fallback to installed-files.txt)
     236          },
     237          "egg_with_module.py": """
     238              def main():
     239                  print("hello world")
     240              """,
     241      }
     242  
     243      def setUp(self):
     244          super().setUp()
     245          build_files(EggInfoPkgPipInstalledNoToplevel.files, prefix=self.site_dir)
     246  
     247  
     248  class ESC[4;38;5;81mEggInfoPkgPipInstalledNoModules(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
     249      files: FilesSpec = {
     250          "egg_with_no_modules_pkg.egg-info": {
     251              "PKG-INFO": "Name: egg_with_no_modules-pkg",
     252              # SOURCES.txt is made from the source archive, and contains files
     253              # (setup.py) that are not present after installation.
     254              "SOURCES.txt": """
     255                  setup.py
     256                  egg_with_no_modules_pkg.egg-info/PKG-INFO
     257                  egg_with_no_modules_pkg.egg-info/SOURCES.txt
     258                  egg_with_no_modules_pkg.egg-info/top_level.txt
     259              """,
     260              # installed-files.txt is written by pip, and is a strictly more
     261              # accurate source than SOURCES.txt as to the installed contents of
     262              # the package.
     263              "installed-files.txt": """
     264                  PKG-INFO
     265                  SOURCES.txt
     266                  top_level.txt
     267              """,
     268              # top_level.txt correctly reflects that no modules are installed
     269              "top_level.txt": b"\n",
     270          },
     271      }
     272  
     273      def setUp(self):
     274          super().setUp()
     275          build_files(EggInfoPkgPipInstalledNoModules.files, prefix=self.site_dir)
     276  
     277  
     278  class ESC[4;38;5;81mEggInfoPkgSourcesFallback(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
     279      files: FilesSpec = {
     280          "sources_fallback_pkg.egg-info": {
     281              "PKG-INFO": "Name: sources_fallback-pkg",
     282              # SOURCES.txt is made from the source archive, and contains files
     283              # (setup.py) that are not present after installation.
     284              "SOURCES.txt": """
     285                  sources_fallback.py
     286                  setup.py
     287                  sources_fallback_pkg.egg-info/PKG-INFO
     288                  sources_fallback_pkg.egg-info/SOURCES.txt
     289              """,
     290              # missing installed-files.txt (i.e. not installed by pip) and
     291              # missing top_level.txt (to trigger fallback to SOURCES.txt)
     292          },
     293          "sources_fallback.py": """
     294              def main():
     295                  print("hello world")
     296              """,
     297      }
     298  
     299      def setUp(self):
     300          super().setUp()
     301          build_files(EggInfoPkgSourcesFallback.files, prefix=self.site_dir)
     302  
     303  
     304  class ESC[4;38;5;81mEggInfoFile(ESC[4;38;5;149mOnSysPath, ESC[4;38;5;149mSiteDir):
     305      files: FilesSpec = {
     306          "egginfo_file.egg-info": """
     307              Metadata-Version: 1.0
     308              Name: egginfo_file
     309              Version: 0.1
     310              Summary: An example package
     311              Home-page: www.example.com
     312              Author: Eric Haffa-Vee
     313              Author-email: eric@example.coms
     314              License: UNKNOWN
     315              Description: UNKNOWN
     316              Platform: UNKNOWN
     317              """,
     318      }
     319  
     320      def setUp(self):
     321          super().setUp()
     322          build_files(EggInfoFile.files, prefix=self.site_dir)
     323  
     324  
     325  # dedent all text strings before writing
     326  orig = _path.create.registry[str]
     327  _path.create.register(str, lambda content, path: orig(DALS(content), path))
     328  
     329  
     330  build_files = _path.build
     331  
     332  
     333  def build_record(file_defs):
     334      return ''.join(f'{name},,\n' for name in record_names(file_defs))
     335  
     336  
     337  def record_names(file_defs):
     338      recording = _path.Recording()
     339      _path.build(file_defs, recording)
     340      return recording.record
     341  
     342  
     343  class ESC[4;38;5;81mFileBuilder:
     344      def unicode_filename(self):
     345          return FS_NONASCII or self.skip("File system does not support non-ascii.")
     346  
     347  
     348  def DALS(str):
     349      "Dedent and left-strip"
     350      return textwrap.dedent(str).lstrip()
     351  
     352  
     353  @requires_zlib()
     354  class ESC[4;38;5;81mZipFixtures:
     355      root = 'test.test_importlib.data'
     356  
     357      def _fixture_on_path(self, filename):
     358          pkg_file = resources.files(self.root).joinpath(filename)
     359          file = self.resources.enter_context(resources.as_file(pkg_file))
     360          assert file.name.startswith('example'), file.name
     361          sys.path.insert(0, str(file))
     362          self.resources.callback(sys.path.pop, 0)
     363  
     364      def setUp(self):
     365          # Add self.zip_name to the front of sys.path.
     366          self.resources = contextlib.ExitStack()
     367          self.addCleanup(self.resources.close)
     368  
     369  
     370  def parameterize(*args_set):
     371      """Run test method with a series of parameters."""
     372  
     373      def wrapper(func):
     374          @functools.wraps(func)
     375          def _inner(self):
     376              for args in args_set:
     377                  with self.subTest(**args):
     378                      func(self, **args)
     379  
     380          return _inner
     381  
     382      return wrapper