def test_custom_executable(self): fn = os.path.join(HERE, 'dummy-0.1-py27-none-any.whl') for executable in 'mypython', None: dstdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, dstdir) w = Wheel(fn) paths = {'prefix': dstdir} for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): paths[key] = os.path.join(dstdir, key) maker = ScriptMaker(None, None) maker.variants = set(['']) maker.executable = executable w.install(paths, maker) # On Windows there will be an exe file, and on POSIX a text file. # The test is structured to not care. p = paths['scripts'] # there should be just one file in the directory - dummy.py/dummy.exe p = os.path.join(p, os.listdir(p)[0]) with open(p, 'rb') as f: data = f.read() if executable is None: expected = fsencode(get_executable()) else: expected = executable.encode('utf-8') expected = b'#!' + expected + b' -E' if not sysconfig.is_python_build(): self.assertIn(expected, data)
def test_custom_executable(self): fn = os.path.join(HERE, 'dummy-0.1-py27-none-any.whl') for executable in 'mypython', None: dstdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, dstdir) w = Wheel(fn) paths = {'prefix': dstdir} for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): paths[key] = os.path.join(dstdir, key) maker = ScriptMaker(None, None) maker.variants = set(['']) maker.executable = executable w.install(paths, maker) # On Windows there will be an exe file, and on POSIX a text file. # The test is structured to not care. p = paths['scripts'] # there should be just one file in the directory - dummy.py/dummy.exe p = os.path.join(p, os.listdir(p)[0]) with open(p, 'rb') as f: data = f.read() if executable is None: expected = fsencode(get_executable()) else: expected = executable.encode('utf-8') expected = b'#!' + expected + b' -E' self.assertIn(expected, data)
def test_verify(self): fn = os.path.join(HERE, "dummy-0.1-py27-none-any.whl") w = Wheel(fn) w.verify() fn = os.path.join(HERE, "bad_wheels", "dummy-0.1-py27-none-any.whl") w = Wheel(fn) self.assertRaises(DistlibException, w.verify)
def test_custom_executable(self): fn = os.path.join(HERE, "dummy-0.1-py27-none-any.whl") for executable in "mypython", None: dstdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, dstdir) w = Wheel(fn) paths = {"prefix": dstdir} for key in ("purelib", "platlib", "headers", "scripts", "data"): paths[key] = os.path.join(dstdir, key) maker = ScriptMaker(None, None) maker.variants = set([""]) maker.executable = executable w.install(paths, maker) # On Windows there will be an exe file, and on POSIX a text file. # The test is structured to not care. p = paths["scripts"] # there should be just one file in the directory - dummy.py/dummy.exe p = os.path.join(p, os.listdir(p)[0]) with open(p, "rb") as f: data = f.read() if executable is None: expected = fsencode(get_executable()) else: expected = executable.encode("utf-8") expected = b"#!" + expected + b" -E" if not sysconfig.is_python_build(): self.assertIn(expected, data)
def __init__(self, wheel_file): wheel = Wheel(wheel_file) assert wheel.is_compatible(), \ "%s is not compatible with this platform" % wheel_file wheel.verify() self.wheel = wheel
def test_update(self): workdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, workdir) fn = "dummy-0.1-py27-none-any.whl" sfn = os.path.join(HERE, fn) dfn = os.path.join(workdir, fn) shutil.copyfile(sfn, dfn) mtime = os.stat(dfn).st_mtime w = Wheel(dfn) modified = w.update(self.wheel_modifier_nop) self.assertFalse(modified) self.assertEqual(mtime, os.stat(dfn).st_mtime) modified = w.update(self.wheel_modifier) self.assertTrue(modified) self.assertLessEqual(mtime, os.stat(dfn).st_mtime) w = Wheel(dfn) w.verify() md = w.metadata self.assertEqual(md.run_requires, [{"requires": ["numpy"]}]) self.assertEquals(md.version, "0.1+1") modified = w.update(self.wheel_modifier_ver) self.assertTrue(modified) self.assertLessEqual(mtime, os.stat(dfn).st_mtime) w = Wheel(dfn) w.verify() md = w.metadata self.assertEqual(md.run_requires, [{"requires": ["numpy"]}]) self.assertEquals(md.version, "0.1+123")
def test_mount(self): fn = os.path.join(HERE, 'dummy-0.1-py27-none-any.whl') w = Wheel(fn) self.assertNotIn(fn, sys.path) w.mount() self.assertIn(fn, sys.path) w.unmount() self.assertNotIn(fn, sys.path)
def test_local_version(self): w = Wheel("dummy-0.1_1.2") self.assertEqual(w.filename, "dummy-0.1_1.2-%s" "-none-any.whl" % PYVER) self.assertEqual(w.name, "dummy") self.assertEqual(w.version, "0.1-1.2") self.assertFalse(w.exists) w.version = "0.1-1.3" self.assertEqual(w.filename, "dummy-0.1_1.3-%s" "-none-any.whl" % PYVER)
def install_wheel(self, wheel: Wheel) -> None: paths = self.environment.get_paths() scripts = distlib.scripts.ScriptMaker(None, None) scripts.executable = self.environment.python_executable scripts.script_template = scripts.script_template.replace( "import sys", "import sys\nsys.path.insert(0, {!r})".format(paths["platlib"]), ) wheel.install(paths, scripts)
def install_wheel(self, wheel: Wheel) -> None: paths = self.environment.get_paths() maker = distlib.scripts.ScriptMaker(None, None) maker.variants = set(("",)) enquoted_executable = distlib.scripts.enquote_executable( self.environment.interpreter.executable ) maker.executable = enquoted_executable wheel.install(paths, maker)
def test_local_version(self): w = Wheel('dummy-0.1_1.2') self.assertEqual(w.filename, 'dummy-0.1_1.2-%s' '-none-any.whl' % PYVER) self.assertEqual(w.name, 'dummy') self.assertEqual(w.version, '0.1-1.2') self.assertFalse(w.exists) w.version = '0.1-1.3' self.assertEqual(w.filename, 'dummy-0.1_1.3-%s' '-none-any.whl' % PYVER)
def test_verify(self): fn = os.path.join(HERE, 'dummy-0.1-py27-none-any.whl') w = Wheel(fn) w.verify() # see issue 115 fn = os.path.join(HERE, 'valid_wheel-0.0.1-py3-none-any.whl') w = Wheel(fn) w.verify() fn = os.path.join(HERE, 'bad_wheels', 'dummy-0.1-py27-none-any.whl') w = Wheel(fn) self.assertRaises(DistlibException, w.verify)
def test_build_tags(self): workdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, workdir) name = 'dummy' version = '0.1' paths = {'prefix': workdir} for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): paths[key] = p = os.path.join(workdir, key) os.makedirs(p) fn = os.path.join(p, '%s_file.txt' % key) with open(fn, 'w') as f: f.write('dummy data - %s' % key) if key in ('purelib', 'platlib'): p = os.path.join(p, '%s-%s.dist-info' % (name, version)) os.makedirs(p) fn = os.path.join(p, 'RECORD') purelib = paths.pop('purelib') platlib = paths.pop('platlib') # Make a pure wheel with default tags paths['purelib'] = purelib wheel = Wheel('%s-%s' % (name, version)) wheel.dirname = workdir wheel.build(paths) expected = { 'name': name, 'version': version, 'pyver': [PYVER], 'abi': ['none'], 'arch': ['any'], 'filename': 'dummy-0.1-%s-none-any.whl' % PYVER, } self.check_built_wheel(wheel, expected) # Make a pure wheel with custom tags pyver = [PYVER[:-1], PYVER] wheel.build(paths, {'pyver': pyver}) expected = { 'name': name, 'version': version, 'pyver': pyver, 'abi': ['none'], 'arch': ['any'], 'filename': 'dummy-0.1-%s-none-any.whl' % '.'.join(pyver), } self.check_built_wheel(wheel, expected) # Make a non-pure wheel with default tags paths.pop('purelib') paths['platlib'] = platlib wheel.build(paths) expected['pyver'] = [IMPVER] expected['abi'] = [ABI] expected['arch'] = [ARCH] expected['filename'] = 'dummy-0.1-%s-%s-%s.whl' % (IMPVER, ABI, ARCH) self.check_built_wheel(wheel, expected)
def __init__(self, wheel_file): wheel = Wheel(wheel_file) if not wheel.is_compatible(): # Workaround for https://bitbucket.org/pypa/distlib/issues/93 log.warning( "WARNING: Distlib reports that %s is not compatible " "with this platform. " "(Note that on some versions of python, " "distlib's detection of compatible ABIs is broken. " "See distlib issue #93.)", wheel_file) wheel.verify() self.wheel = wheel
def get_metadata_from_wheel(wheel_path): # type: (S) -> Dict[Any, Any] if not isinstance(wheel_path, six.string_types): raise TypeError( "Expected string instance, received {0!r}".format(wheel_path)) try: dist = Wheel(wheel_path) except Exception: pass metadata = dist.metadata name = metadata.name version = metadata.version requires = [] extras_keys = getattr(metadata, "extras", []) extras = {k: [] for k in extras_keys} for req in getattr(metadata, "run_requires", []): parsed_req = init_requirement(req) parsed_marker = parsed_req.marker if parsed_marker: extra = get_extra_name_from_marker(parsed_marker) if extra is None: requires.append(parsed_req) continue if extra not in extras: extras[extra] = [] parsed_req = strip_extras_markers_from_requirement(parsed_req) extras[extra].append(parsed_req) else: requires.append(parsed_req) return { "name": name, "version": version, "requires": requires, "extras": extras }
def ireq_as_line(ireq: InstallRequirement, environment: Environment) -> str: """Formats an `InstallRequirement` instance as a PEP 508 dependency string. Generic formatter for pretty printing InstallRequirements to the terminal in a less verbose way than using its `__str__` method. :param :class:`InstallRequirement` ireq: A pip **InstallRequirement** instance. :return: A formatted string for prettyprinting :rtype: str """ if ireq.editable: line = "-e {}".format(ireq.link) else: if not ireq.req: ireq.req = parse_requirement("dummy @" + ireq.link.url) # type: ignore wheel = Wheel(environment.build(ireq)) ireq.req.name = wheel.name # type: ignore line = _requirement_to_str_lowercase_name(cast(PRequirement, ireq.req)) assert ireq.req if not ireq.req.marker and ireq.markers: line = f"{line}; {ireq.markers}" return line
def get_metadata(self, allow_all_wheels: bool = True) -> Optional[Metadata]: """Get the metadata of the candidate. For editable requirements, egg info are produced, otherwise a wheel is built. """ if self.metadata is not None: return self.metadata ireq = self.ireq if self.link and not ireq.link: ireq.link = self.link built = self.environment.build(ireq, self.hashes, allow_all_wheels) if self.req.editable: if not self.req.is_local_dir and not self.req.is_vcs: raise RequirementError( "Editable installation is only supported for " "local directory and VCS location." ) sdist = get_sdist(built) self.metadata = sdist.metadata if sdist else None else: # It should be a wheel path. self.wheel = Wheel(built) self.metadata = self.wheel.metadata if not self.name: self.name = self.metadata.name self.req.name = self.name if not self.version: self.version = self.metadata.version self.link = ireq.link return self.metadata
def ireq_as_line(ireq: InstallRequirement, environment: Environment) -> str: """Formats an `InstallRequirement` instance as a PEP 508 dependency string. Generic formatter for pretty printing InstallRequirements to the terminal in a less verbose way than using its `__str__` method. :param :class:`InstallRequirement` ireq: A pip **InstallRequirement** instance. :return: A formatted string for prettyprinting :rtype: str """ if ireq.editable: line = "-e {}".format(ireq.link) else: if not ireq.req: ireq.req = parse_requirement("dummy @" + ireq.link.url) wheel = Wheel(environment.build(ireq)) ireq.req.name = wheel.name line = _requirement_to_str_lowercase_name(ireq.req) if str(ireq.req.marker) != str(ireq.markers): if not ireq.req.marker: line = "{}; {}".format(line, ireq.markers) else: name, markers = line.split(";", 1) markers = Marker(markers) & ireq.markers line = "{}; {}".format(name, markers) return line
def test_build_single_module(fixture_project): project = fixture_project("demo-module") assert project.meta.version == "0.1.0" actions.do_build(project) tar_names = get_tarball_names(project.root / "dist/demo-module-0.1.0.tar.gz") for name in [ "foo_module.py", "bar_module.py", "LICENSE", "pyproject.toml", "PKG-INFO", ]: assert f"demo-module-0.1.0/{name}" in tar_names zip_names = get_wheel_names(project.root / "dist/demo_module-0.1.0-py3-none-any.whl") for name in ["foo_module.py", "bar_module.py"]: assert name in zip_names for name in ("pyproject.toml", "LICENSE"): assert name not in zip_names assert Wheel( (project.root / "dist/demo_module-0.1.0-py3-none-any.whl").as_posix()).metadata
def test_valid_filename(self): attrs = ('name', 'version', 'buildver', 'pyver', 'abi', 'arch') cases = ( ('pkg-1.0.0-cp32.cp33-noabi-noarch.whl', ('pkg', '1.0.0', '', ['cp32', 'cp33'], ['noabi'], ['noarch'])), ('package-1.0.0-cp33-noabi-linux_x86_64.whl', ('package', '1.0.0', '', ['cp33'], ['noabi'], ['linux_x86_64'])), ('test-1.0-1st-py2.py3-none-win32.whl', ('test', '1.0', '1st', ['py2', 'py3'], ['none'], ['win32'])), ('Pillow-2.8.1-cp27-none-macosx_10_6_intel.' 'macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.' 'macosx_10_10_x86_64.whl', ('Pillow', '2.8.1', '', ['cp27'], ['none'], [ 'macosx_10_6_intel', 'macosx_10_9_intel', 'macosx_10_9_x86_64', 'macosx_10_10_intel', 'macosx_10_10_x86_64' ])), ) for name, values in cases: w = Wheel(name) self.assertEqual(w.wheel_version, (1, 1)) self.assertEqual(w.filename, name) for attr, value in zip(attrs, values): self.assertEqual(getattr(w, attr), value)
def load(self, whl, uuid): w = Wheel(fetcher.fetch(whl, uuid)) return ( canonicalize_name(w.name), w.version, # Argh distlib.metadata.Metadata.dependencies is broken! w.metadata.todict().get('requires_dist', []))
def test_build_distributions(tmp_path, core): project = core.create_project() actions.do_build(project, dest=tmp_path.as_posix()) wheel = Wheel(next(tmp_path.glob("*.whl")).as_posix()) assert wheel.name == "pdm" tarball = next(tmp_path.glob("*.tar.gz")) assert tarball.exists()
def test_build_tags(self): workdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, workdir) name = "dummy" version = "0.1" paths = {"prefix": workdir} for key in ("purelib", "platlib", "headers", "scripts", "data"): paths[key] = p = os.path.join(workdir, key) os.makedirs(p) fn = os.path.join(p, "%s_file.txt" % key) with open(fn, "w") as f: f.write("dummy data - %s" % key) if key in ("purelib", "platlib"): p = os.path.join(p, "%s-%s.dist-info" % (name, version)) os.makedirs(p) fn = os.path.join(p, "RECORD") purelib = paths.pop("purelib") platlib = paths.pop("platlib") # Make a pure wheel with default tags paths["purelib"] = purelib wheel = Wheel("%s-%s" % (name, version)) wheel.dirname = workdir wheel.build(paths) expected = { "name": name, "version": version, "pyver": [PYVER], "abi": ["none"], "arch": ["any"], "filename": "dummy-0.1-%s-none-any.whl" % PYVER, } self.check_built_wheel(wheel, expected) # Make a pure wheel with custom tags pyver = [PYVER[:-1], PYVER] wheel.build(paths, {"pyver": pyver}) expected = { "name": name, "version": version, "pyver": pyver, "abi": ["none"], "arch": ["any"], "filename": "dummy-0.1-%s-none-any.whl" % ".".join(pyver), } self.check_built_wheel(wheel, expected) # Make a non-pure wheel with default tags paths.pop("purelib") paths["platlib"] = platlib wheel.build(paths) expected["pyver"] = [IMPVER] expected["abi"] = [ABI] expected["arch"] = [ARCH] expected["filename"] = "dummy-0.1-%s-%s-%s.whl" % (IMPVER, ABI, ARCH) self.check_built_wheel(wheel, expected)
def test_version_incompatibility(self): class Warner(object): def __call__(self, wheel_version, file_version): self.wheel_version = wheel_version self.file_version = file_version fn = os.path.join(HERE, 'dummy-0.1-py27-none-any.whl') dstdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, dstdir) w = Wheel(fn) paths = {'prefix': dstdir} for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): paths[key] = os.path.join(dstdir, key) warner = Warner() maker = ScriptMaker(None, None) w.install(paths, maker, warner=warner) self.assertEqual(warner.wheel_version, w.wheel_version) self.assertEqual(warner.file_version, (2, 0)) # Now set the wheel's instance to the higher value and ensure # warner isn't called warner = Warner() w.wheel_version = (2, 0) w.install(paths, maker, warner=warner) self.assertFalse(hasattr(warner, 'wheel_version')) self.assertFalse(hasattr(warner, 'file_version'))
def do_build_and_install(self, dist): srcdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, srcdir) dstdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, dstdir) paths = install_dist(dist, srcdir) paths['prefix'] = srcdir w = Wheel() w.name = paths.pop('name') w.version = paths.pop('version') w.dirname = srcdir pathname = w.build(paths) self.assertTrue(os.path.exists(pathname)) paths = {'prefix': dstdir} for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): paths[key] = os.path.join(dstdir, key) w = Wheel(pathname) executable = os.path.join(paths['scripts'], 'python') dist = w.install(paths, executable=executable) self.assertIsNotNone(dist) self.assertEqual(dist.name, w.name) self.assertEqual(dist.version, w.version) os.remove(pathname) sm = Manifest(srcdir) sm.findall() sfiles = set([os.path.relpath(p, srcdir) for p in sm.allfiles]) dm = Manifest(dstdir) dm.findall() dfiles = set([os.path.relpath(p, dstdir) for p in dm.allfiles]) omitted = sfiles - dfiles omitted = omitted.pop() endings = os.path.join('.dist-info', 'WHEEL'), '.pyc', '.pyo' self.assertTrue(omitted.endswith(endings))
def __install_wheel( self, filepath: str, force: bool, upgrade: bool, options: dict, ) -> InstalledDistribution: '''Install wheel to selected paths.''' wheel = Wheel(filepath) try: wheel.verify() return wheel.install( paths=self.distribution_path.paths, maker=ScriptMaker(None, None), # bytecode_hashed_invalidation=True ) except DistlibException: print('wheel did not pass validation')
def install_wheels(wheels_folder, install_folder): logging.getLogger('distlib').setLevel(logging.ERROR) if not os.path.exists(install_folder): os.makedirs(install_folder) from distlib.wheel import Wheel from distlib.scripts import ScriptMaker paths = { 'prefix': '', 'purelib': install_folder, 'platlib': install_folder, 'scripts': '', 'headers': '', 'data': ''} files = os.listdir(wheels_folder) for f in [os.path.join(wheels_folder, f) for f in files]: wheel = Wheel(f) wheel.install(paths, ScriptMaker(None, None), lib_only=True)
def handle(self, requester, data): requirement = data['requirement'] dependencies = Wheel(data['wheel']).metadata.dependencies extra_sections = set(util.parse_requirement(requirement).extras or ()) # Honor the `extras` section of the requirement we just received found = dependencies.get('install', []) for section, items in dependencies.get('extras', {}).items(): if section in extra_sections: found.extend(items) # Telling the world about the dependencies we found for dependency in found: self.emit('dependency_found', self.name, requirement=util.safe_name(dependency), dependency_of=requirement) # Keep the message flowing return {'requirement': requirement, 'wheel': data['wheel']}
def locate(simple_url, pkg, dest, work): locator = SimpleScrapingLocator(simple_url) dist = locator.locate(pkg) url = list(dist.download_urls)[0] download = request.urlopen(url) fname = url.split('/')[-1] with open(os.path.join(work, fname), 'wb') as f: f.write(download.read()) wheel = Wheel(os.path.join(work, fname)) print(wheel.name) paths = { 'purelib': dest, 'platlib': dest, 'prefix': dest, 'headers': dest, 'scripts': dest, 'data': dest, } maker = ScriptMaker(None, None) wheel.install(paths, maker)
def test_info(self): fn = os.path.join(HERE, 'dummy-0.1-py27-none-any.whl') w = Wheel(fn) actual = w.info actual.pop('Generator', None) expected = { 'Root-Is-Purelib': 'true', 'Tag': 'py27-none-any', 'Wheel-Version': '2.0' } self.assertEqual(actual, expected)
def handle(self, requester, data): requirement = data['requirement'] wheel = Wheel(data['wheel']) run_time_dependencies = wheel.metadata.requires_dist for spec in run_time_dependencies: # Packages might declare their "extras" here, so let's split it dependency, extra = (';' in spec and spec or spec + ';').split(';') self.emit('dependency_found', self.name, requirement=util.safe_name(dependency), dependency_of=requirement) return {'requirement': requirement, 'wheel': data['wheel']}
def wheel(platform_name, wheel_dir, pip_args): mkdirp(wheel_dir) # Make the wheels using the platform default # Do this in a tempdir in case there are already wheels in the output # directory with tmpdir() as tempdir: import pip ret = pip.main(['wheel', '--wheel-dir', tempdir] + list(pip_args)) if ret: return ret # Then rename any of the platform-specific wheels created for wheel_filename in os.listdir(tempdir): wheel_obj = Wheel(wheel_filename) if wheel_obj.arch != ['any']: wheel_obj.arch = [platform_name] dst = os.path.join(wheel_dir, wheel_obj.filename) else: dst = os.path.join(wheel_dir, wheel_filename) # And copy to the output directory shutil.copy(os.path.join(tempdir, wheel_filename), dst)
def test_mount_extensions(self): if PYVER == 'py27': fn = 'minimext-0.1-cp27-none-linux_x86_64.whl' elif PYVER == 'py32': fn = 'minimext-0.1-cp32-cp32mu-linux_x86_64.whl' elif PYVER == 'py33': fn = 'minimext-0.1-cp33-cp33m-linux_x86_64.whl' else: fn = None if not fn: # pragma: no cover raise unittest.SkipTest('Suitable wheel not found.') fn = os.path.join(HERE, fn) w = Wheel(fn) if not is_compatible(w): # pragma: no cover raise unittest.SkipTest('Wheel not suitable for mounting.') self.assertRaises(ImportError, __import__, 'minimext') w.mount() mod = __import__('minimext') self.assertIs(mod, sys.modules['minimext']) self.assertEqual(mod.fib(10), 55) w.unmount() del sys.modules['minimext'] self.assertRaises(ImportError, __import__, 'minimext')
def test_valid_name(self): attrs = ('name', 'version', 'buildver', 'pyver', 'abi', 'arch') pyver = PYVER cases = ( ('pkg-1.0.0', ('pkg', '1.0.0', '', [PYVER], ['none'], ['any'])), ('test-1.0-1st', ('test', '1.0', '1st', [PYVER], ['none'], ['any' ])), (None, ('dummy', '0.1', '', [PYVER], ['none'], ['any'])), ) ENDING = '-%s-none-any.whl' % PYVER for name, values in cases: w = Wheel(name) self.assertEqual(w.wheel_version, (1, 1)) self.assertTrue(w.filename.endswith(ENDING)) for attr, value in zip(attrs, values): self.assertEqual(getattr(w, attr), value)
def do_build_and_install(self, dist): srcdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, srcdir) dstdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, dstdir) paths = install_dist(dist, srcdir) paths['prefix'] = srcdir w = Wheel() w.name = paths.pop('name') w.version = paths.pop('version') w.dirname = srcdir pathname = w.build(paths) self.assertTrue(os.path.exists(pathname)) paths = {'prefix': dstdir} for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): paths[key] = os.path.join(dstdir, key) w = Wheel(pathname) maker = ScriptMaker(None, None, add_launchers=False) maker.executable = os.path.join(paths['scripts'], 'python') dist = w.install(paths, maker) self.assertIsNotNone(dist) self.assertEqual(dist.name, w.name) self.assertEqual(dist.version, w.version) shared = dist.shared_locations self.assertTrue(shared) os.remove(pathname) sm = Manifest(srcdir) sm.findall() sfiles = set([os.path.relpath(p, srcdir) for p in sm.allfiles]) dm = Manifest(dstdir) dm.findall() dfiles = set([os.path.relpath(p, dstdir) for p in dm.allfiles]) omitted = sfiles - dfiles omitted = omitted.pop() endings = os.path.join('.dist-info', 'WHEEL'), '.pyc', '.pyo' self.assertTrue(omitted.endswith(endings))
def get_metadata(self, allow_all_wheels: bool = True, raising: bool = False) -> Optional[Metadata]: """Get the metadata of the candidate. For editable requirements, egg info are produced, otherwise a wheel is built. If raising is True, error will pop when the package fails to build. """ if self.metadata is not None: return self.metadata ireq = self.ireq if self.link and not ireq.link: ireq.link = self.link try: built = self.environment.build(ireq, self.hashes, allow_all_wheels) except BuildError: if raising: raise termui.logger.warn( "Failed to build package, try parsing project files.") meta_dict = SetupReader.read_from_directory( ireq.unpacked_source_directory) meta_dict.update(summary="UNKNOWN") meta_dict["requires_python"] = meta_dict.pop( "python_requires", None) self.metadata = Namespace(**meta_dict) else: if self.req.editable: if not self.req.is_local_dir and not self.req.is_vcs: raise RequirementError( "Editable installation is only supported for " "local directory and VCS location.") sdist = get_sdist(built) self.metadata = sdist.metadata if sdist else None else: # It should be a wheel path. self.wheel = Wheel(built) self.metadata = self.wheel.metadata if not self.name: self.name = self.metadata.name self.req.name = self.name if not self.version: self.version = self.metadata.version self.link = ireq.link return self.metadata
def parse_filename(filename, name=None): """ Parse a name and version out of a filename """ version = None for ext in ALL_EXTENSIONS: if filename.endswith(ext): if ext == '.whl': wheel = Wheel(filename) return wheel.name, wheel.version trimmed = filename[:-len(ext)] parsed = split_filename(trimmed, name) if parsed is None: break else: parsed_name, version = parsed[:2] break if version is None: raise ValueError("Cannot parse package file '%s'" % filename) if name is None: name = parsed_name return normalize_name(name), version
def test_mount_extensions(self): if PYVER == 'py27': fn = 'minimext-0.1-cp27-none-linux_x86_64.whl' elif PYVER == 'py32': fn = 'minimext-0.1-cp32-cp32mu-linux_x86_64.whl' elif PYVER == 'py33': fn = 'minimext-0.1-cp33-cp33m-linux_x86_64.whl' else: fn = None if not fn: # pragma: no cover raise unittest.SkipTest('Suitable wheel not found.') fn = os.path.join(HERE, fn) w = Wheel(fn) if not w.is_compatible() or not w.is_mountable(): # pragma: no cover raise unittest.SkipTest('Wheel not suitable for mounting.') self.assertRaises(ImportError, __import__, 'minimext') w.mount() mod = __import__('minimext') self.assertIs(mod, sys.modules['minimext']) self.assertEqual(mod.fib(10), 55) w.unmount() del sys.modules['minimext'] self.assertRaises(ImportError, __import__, 'minimext')
def do_build_and_install(self, dist): srcdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, srcdir) dstdir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, dstdir) paths = install_dist(dist, srcdir) paths["prefix"] = srcdir w = Wheel() w.name = paths.pop("name") w.version = paths.pop("version") w.dirname = srcdir pathname = w.build(paths) self.assertTrue(os.path.exists(pathname)) paths = {"prefix": dstdir} for key in ("purelib", "platlib", "headers", "scripts", "data"): paths[key] = os.path.join(dstdir, key) w = Wheel(pathname) maker = ScriptMaker(None, None, add_launchers=False) maker.executable = os.path.join(paths["scripts"], "python") dist = w.install(paths, maker) self.assertIsNotNone(dist) self.assertEqual(dist.name, w.name) self.assertEqual(dist.version, w.version) shared = dist.shared_locations self.assertTrue(shared) os.remove(pathname) sm = Manifest(srcdir) sm.findall() sfiles = set([os.path.relpath(p, srcdir) for p in sm.allfiles]) dm = Manifest(dstdir) dm.findall() dfiles = set([os.path.relpath(p, dstdir) for p in dm.allfiles]) omitted = sfiles - dfiles omitted = omitted.pop() endings = os.path.join(".dist-info", "WHEEL"), ".pyc", ".pyo" self.assertTrue(omitted.endswith(endings))
def test_mount_extensions(self): if PYVER == "py27": fn = "minimext-0.1-cp27-none-linux_x86_64.whl" elif PYVER == "py32": fn = "minimext-0.1-cp32-cp32mu-linux_x86_64.whl" elif PYVER == "py33": fn = "minimext-0.1-cp33-cp33m-linux_x86_64.whl" else: fn = None if not fn: # pragma: no cover raise unittest.SkipTest("Suitable wheel not found.") fn = os.path.join(HERE, fn) w = Wheel(fn) if not w.is_compatible() or not w.is_mountable(): # pragma: no cover raise unittest.SkipTest("Wheel not suitable for mounting.") self.assertRaises(ImportError, __import__, "minimext") w.mount() mod = __import__("minimext") self.assertIs(mod, sys.modules["minimext"]) self.assertEqual(mod.fib(10), 55) w.unmount() del sys.modules["minimext"] self.assertRaises(ImportError, __import__, "minimext")
def pack(project_dir, wheelhouse, work_dir): dist_path = os.path.join(project_dir, 'dist-info', 'pydist.json') md = Metadata(path=dist_path) wheel = Wheel() wheel.name = md.name wheel.version = md.version dest_dist = os.path.join(work_dir, '{}.dist-info'.format(md.name)) os.makedirs(dest_dist) shutil.copyfile(dist_path, os.path.join(dest_dist, 'pydist.json')) for pkg_dir in os.listdir(os.path.join(project_dir, 'src')): shutil.copytree(os.path.join(project_dir, 'src', pkg_dir), os.path.join(work_dir, pkg_dir)) paths = { 'purelib': work_dir, } wheel.dirname = wheelhouse wheel.build(paths)
def build_wheel(distname, options): result = None r = parse_requirement(distname) if not r: print('Invalid requirement: %r' % distname) else: dist = INSTALLED_DISTS.get_distribution(r.name) if dist: print('Can\'t build a wheel from already-installed ' 'distribution %s' % dist.name_and_version) else: workdir = tempfile.mkdtemp() # where the Wheel input files will live try: paths = install_dist(distname, workdir, options) paths['prefix'] = workdir wheel = Wheel() wheel.name = paths.pop('name') wheel.version = paths.pop('version') wheel.dirname = options.destdir wheel.build(paths) result = wheel finally: shutil.rmtree(workdir) return result
def handle(self, requester, data): name = data['requirement'].name wheel = Wheel(data['wheel']) wheel.install(get_distribution_paths(name)) return data