1#!/usr/bin/env python3 2# Copyright 2023 The Bazel Authors. All rights reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16 17import os 18import platform 19import subprocess 20import sys 21import unittest 22from pathlib import Path 23 24from python.runfiles import runfiles 25 26 27class PipWhlModsTest(unittest.TestCase): 28 maxDiff = None 29 30 @staticmethod 31 def _get_bazel_pkg_dir_name(env_var: str) -> str: 32 a_file = Path(os.environ.get(env_var).split(" ")[0]) 33 head = a_file 34 while head.parent.name: 35 head = head.parent 36 37 return head.name 38 39 @classmethod 40 def setUpClass(cls): 41 cls._wheel_pkg_dir = cls._get_bazel_pkg_dir_name("WHEEL_PKG") 42 cls._requests_pkg_dir = cls._get_bazel_pkg_dir_name("REQUESTS_PKG") 43 44 def wheel_pkg_dir(self) -> Path: 45 return self._wheel_pkg 46 47 def test_build_content_and_data(self): 48 r = runfiles.Create() 49 rpath = r.Rlocation( 50 "{}/generated_file.txt".format( 51 self._wheel_pkg_dir, 52 ), 53 ) 54 generated_file = Path(rpath) 55 self.assertTrue(generated_file.exists()) 56 57 content = generated_file.read_text().rstrip() 58 self.assertEqual(content, "Hello world from build content file") 59 60 def test_copy_files(self): 61 r = runfiles.Create() 62 rpath = r.Rlocation( 63 "{}/copied_content/file.txt".format( 64 self._wheel_pkg_dir, 65 ) 66 ) 67 copied_file = Path(rpath) 68 self.assertTrue(copied_file.exists()) 69 70 content = copied_file.read_text().rstrip() 71 self.assertEqual(content, "Hello world from copied file") 72 73 def test_copy_executables(self): 74 executable_name = ( 75 "executable.exe" if platform.system() == "windows" else "executable.py" 76 ) 77 78 r = runfiles.Create() 79 rpath = r.Rlocation( 80 "{}/copied_content/{}".format( 81 self._wheel_pkg_dir, 82 executable_name, 83 ) 84 ) 85 executable = Path(rpath) 86 self.assertTrue(executable.exists()) 87 88 proc = subprocess.run( 89 [sys.executable, str(executable)], 90 check=True, 91 stdout=subprocess.PIPE, 92 stderr=subprocess.PIPE, 93 ) 94 stdout = proc.stdout.decode("utf-8").strip() 95 self.assertEqual(stdout, "Hello world from copied executable") 96 97 def test_data_exclude_glob(self): 98 current_wheel_version = "0.40.0" 99 100 r = runfiles.Create() 101 dist_info_dir = "{}/site-packages/wheel-{}.dist-info".format( 102 self._wheel_pkg_dir, 103 current_wheel_version, 104 ) 105 106 # Note: `METADATA` is important as it's consumed by https://docs.python.org/3/library/importlib.metadata.html 107 # `METADATA` is expected to be there to show dist-info files are included in the runfiles. 108 metadata_path = r.Rlocation("{}/METADATA".format(dist_info_dir)) 109 110 # However, `WHEEL` was explicitly excluded, so it should be missing 111 wheel_path = r.Rlocation("{}/WHEEL".format(dist_info_dir)) 112 113 self.assertTrue(Path(metadata_path).exists(), f"Could not find {metadata_path}") 114 self.assertFalse( 115 Path(wheel_path).exists(), f"Expected to not find {wheel_path}" 116 ) 117 118 def test_extra(self): 119 # This test verifies that annotations work correctly for pip packages with extras 120 # specified, in this case requests[security]. 121 r = runfiles.Create() 122 rpath = r.Rlocation( 123 "{}/generated_file.txt".format( 124 self._requests_pkg_dir, 125 ), 126 ) 127 generated_file = Path(rpath) 128 self.assertTrue(generated_file.exists()) 129 130 content = generated_file.read_text().rstrip() 131 self.assertEqual(content, "Hello world from requests") 132 133 def test_patches(self): 134 current_wheel_version = "2.25.1" 135 136 # This test verifies that the patches are applied to the wheel. 137 r = runfiles.Create() 138 metadata_path = "{}/site-packages/requests-{}.dist-info/METADATA".format( 139 self._requests_pkg_dir, 140 current_wheel_version, 141 ) 142 143 metadata = Path(r.Rlocation(metadata_path)) 144 self.assertIn( 145 "Summary: Python HTTP for Humans. Patched.", 146 metadata.read_text().splitlines(), 147 ) 148 149 150if __name__ == "__main__": 151 unittest.main() 152