def get_package_from_file(cls, file_path): # type: (Path) -> Package if file_path.suffix == ".whl": meta = pkginfo.Wheel(str(file_path)) else: # Assume sdist meta = pkginfo.SDist(str(file_path)) package = Package(meta.name, meta.version) package.source_type = "file" package.source_url = file_path.as_posix() package.description = meta.summary for req in meta.requires_dist: dep = dependency_from_pep_508(req) for extra in dep.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dep) if not dep.is_optional(): package.requires.append(dep) if meta.requires_python: package.python_versions = meta.requires_python return package
def search(self, query): results = [] search = {"q": query} response = session().get(self._url + "search", params=search) content = parse(response.content, namespaceHTMLElements=False) for result in content.findall(".//*[@class='package-snippet']"): name = result.find("h3/*[@class='package-snippet__name']").text version = result.find( "h3/*[@class='package-snippet__version']").text if not name or not version: continue description = result.find( "p[@class='package-snippet__description']").text if not description: description = "" try: result = Package(name, version, description) result.description = to_str(description.strip()) results.append(result) except ParseVersionError: self._log( 'Unable to parse version "{}" for the {} package, skipping' .format(version, name), level="debug", ) return results
def get_package_from_file(cls, file_path): # type: (Path) -> Package info = Inspector().inspect(file_path) if not info["name"]: raise RuntimeError( "Unable to determine the package name of {}".format(file_path)) package = Package(info["name"], info["version"]) package.source_type = "file" package.source_url = file_path.as_posix() package.description = info["summary"] for req in info["requires_dist"]: dep = dependency_from_pep_508(req) for extra in dep.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dep) if not dep.is_optional(): package.requires.append(dep) if info["requires_python"]: package.python_versions = info["requires_python"] return package
def search(self, query, mode=0): results = [] search = {"name": query} if mode == self.SEARCH_FULLTEXT: search["summary"] = query client = ServerProxy("https://pypi.python.org/pypi") hits = client.search(search, "or") for hit in hits: try: result = Package(hit["name"], hit["version"], hit["version"]) result.description = to_str(hit["summary"]) results.append(result) except ParseVersionError: self._log( 'Unable to parse version "{}" for the {} package, skipping'.format( hit["version"], hit["name"] ), level="debug", ) return results
def load(cls, env): # type: (Env) -> InstalledRepository """ Load installed packages. For now, it uses the pip "freeze" command. """ repo = cls() seen = set() for entry in env.sys_path: for distribution in sorted( metadata.distributions(path=[entry]), key=lambda d: str(d._path), ): name = distribution.metadata["name"] version = distribution.metadata["version"] package = Package(name, version, version) package.description = distribution.metadata.get("summary", "") if package.name in seen: continue seen.add(package.name) repo.add_package(package) path = Path(str(distribution._path)) is_standard_package = True try: path.relative_to(env.site_packages) except ValueError: is_standard_package = False if is_standard_package: continue src_path = env.path / "src" # A VCS dependency should have been installed # in the src directory. If not, it's a path dependency try: path.relative_to(src_path) from poetry.vcs.git import Git git = Git() revision = git.rev_parse("HEAD", src_path / package.name).strip() url = git.remote_url(src_path / package.name) package.source_type = "git" package.source_url = url package.source_reference = revision except ValueError: package.source_type = "directory" package.source_url = str(path.parent) return repo
def package(self, name: str, version: str, extras: Union[list, None] = None) -> Package: try: index = self._packages.index(Package(name, version, version)) return self._packages[index] except ValueError: if extras is None: extras = [] release_info = self.get_release_info(name, version) package = Package(name, version, version) requires_dist = release_info['requires_dist'] or [] for req in requires_dist: try: dependency = dependency_from_pep_508(req) except InvalidMarker: # Invalid marker # We strip the markers hoping for the best req = req.split(';')[0] dependency = dependency_from_pep_508(req) if dependency.extras: for extra in dependency.extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dependency) if not dependency.is_optional(): package.requires.append(dependency) # Adding description package.description = release_info.get('summary', '') # Adding hashes information package.hashes = release_info['digests'] # Activate extra dependencies for extra in extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] self._packages.append(package) return package
def search(self, query, mode=0): results = [] search = {'name': query} if mode == self.SEARCH_FULLTEXT: search['summary'] = query client = ServerProxy('https://pypi.python.org/pypi') hits = client.search(search, 'or') for hit in hits: result = Package(hit['name'], hit['version'], hit['version']) result.description = to_str(hit['summary']) results.append(result) return results
def search(self, query, mode=0): results = [] search = {"name": query} if mode == self.SEARCH_FULLTEXT: search["summary"] = query client = ServerProxy("https://pypi.python.org/pypi") hits = client.search(search, "or") for hit in hits: result = Package(hit["name"], hit["version"], hit["version"]) result.description = to_str(hit["summary"]) results.append(result) return results
def search_for_file(self, dependency): # type: (FileDependency) -> List[Package] package = Package(dependency.name, dependency.pretty_constraint) package.source_type = "file" package.source_url = dependency.path.as_posix() package.description = dependency.metadata.summary for req in dependency.metadata.requires_dist: package.requires.append(dependency_from_pep_508(req)) if dependency.metadata.requires_python: package.python_versions = dependency.metadata.requires_python if dependency.metadata.platforms: package.platform = " || ".join(dependency.metadata.platforms) package.hashes = [dependency.hash()] return [package]
def search_for_file(self, dependency): # type: (FileDependency) -> List[Package] if dependency.path.suffix == ".whl": meta = pkginfo.Wheel(str(dependency.full_path)) else: # Assume sdist meta = pkginfo.SDist(str(dependency.full_path)) if dependency.name != meta.name: # For now, the dependency's name must match the actual package's name raise RuntimeError( "The dependency name for {} does not match the actual package's name: {}".format( dependency.name, meta.name ) ) package = Package(meta.name, meta.version) package.source_type = "file" package.source_url = dependency.path.as_posix() package.description = meta.summary for req in meta.requires_dist: dep = dependency_from_pep_508(req) for extra in dep.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dep) if not dep.is_optional(): package.requires.append(dep) if meta.requires_python: package.python_versions = meta.requires_python package.hashes = [dependency.hash()] for extra in dependency.extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] return [package]
def __init__( self, path, # type: Path category='main', # type: str optional=False, # type: bool base=None, # type: Path develop=False # type: bool ): from . import dependency_from_pep_508 self._path = path self._base = base self._full_path = path self._develop = develop if self._base and not self._path.is_absolute(): self._full_path = self._base / self._path if not self._full_path.exists(): raise ValueError('Directory {} does not exist'.format(self._path)) if self._full_path.is_file(): raise ValueError('{} is a file, expected a directory'.format( self._path)) # Checking content to dertermine actions setup = self._full_path / 'setup.py' pyproject = TomlFile(self._full_path / 'pyproject.toml') has_poetry = False if pyproject.exists(): pyproject_content = pyproject.read(True) has_poetry = ('tool' in pyproject_content and 'poetry' in pyproject_content['tool']) if not setup.exists() and not has_poetry: raise ValueError( 'Directory {} does not seem to be a Python package'.format( self._full_path)) if has_poetry: from poetry.masonry.builders import SdistBuilder from poetry.poetry import Poetry poetry = Poetry.create(self._full_path) builder = SdistBuilder(poetry, NullVenv(), NullIO()) with setup.open('w') as f: f.write(decode(builder.build_setup())) self._package = poetry.package else: from poetry.packages import Package # Execute egg_info current_dir = os.getcwd() os.chdir(str(self._full_path)) try: cwd = base venv = Venv.create(NullIO(), cwd=cwd) venv.run('python', 'setup.py', 'egg_info') finally: os.chdir(current_dir) egg_info = list(self._full_path.glob('*.egg-info'))[0] meta = pkginfo.UnpackedSDist(str(egg_info)) if meta.requires_dist: reqs = list(meta.requires_dist) else: reqs = [] requires = egg_info / 'requires.txt' if requires.exists(): with requires.open() as f: reqs = parse_requires(f.read()) package = Package(meta.name, meta.version) package.description = meta.summary for req in reqs: package.requires.append(dependency_from_pep_508(req)) if meta.requires_python: package.python_versions = meta.requires_python if meta.platforms: platforms = [ p for p in meta.platforms if p.lower() != 'unknown' ] if platforms: package.platform = ' || '.join(platforms) self._package = package self._package.source_type = 'directory' self._package.source_reference = str(self._path) super(DirectoryDependency, self).__init__(self._package.name, self._package.version, category=category, optional=optional, allows_prereleases=True)
def package( self, name, # type: str version, # type: str extras=None, # type: (Union[list, None]) ): # type: (...) -> Union[Package, None] if extras is None: extras = [] release_info = self.get_release_info(name, version) package = Package(name, version, version) requires_dist = release_info["requires_dist"] or [] for req in requires_dist: try: dependency = dependency_from_pep_508(req) except InvalidMarker: # Invalid marker # We strip the markers hoping for the best req = req.split(";")[0] dependency = dependency_from_pep_508(req) except ValueError: # Likely unable to parse constraint so we skip it self._log( "Invalid constraint ({}) found in {}-{} dependencies, " "skipping".format(req, package.name, package.version), level="debug", ) continue if dependency.in_extras: for extra in dependency.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dependency) if not dependency.is_optional(): package.requires.append(dependency) # Adding description package.description = release_info.get("summary", "") if release_info["requires_python"]: package.python_versions = release_info["requires_python"] if release_info["platform"]: package.platform = release_info["platform"] # Adding hashes information package.hashes = release_info["digests"] # Activate extra dependencies for extra in extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] return package
def package(self, name: str, version: str, extras: Union[list, None] = None) -> Package: try: index = self._packages.index(Package(name, version, version)) return self._packages[index] except ValueError: if extras is None: extras = [] release_info = self.get_release_info(name, version) package = Package(name, version, version) for req in release_info['requires_dist']: req = InstallRequirement.from_line(req) name = req.name version = str(req.req.specifier) dependency = Dependency(name, version, optional=req.markers) is_extra = False if req.markers: # Setting extra dependencies and requirements requirements = self._convert_markers(req.markers._markers) if 'python_version' in requirements: ors = [] for or_ in requirements['python_version']: ands = [] for op, version in or_: ands.append(f'{op}{version}') ors.append(' '.join(ands)) dependency.python_versions = ' || '.join(ors) if 'sys_platform' in requirements: ors = [] for or_ in requirements['sys_platform']: ands = [] for op, platform in or_: ands.append(f'{op}{platform}') ors.append(' '.join(ands)) dependency.platform = ' || '.join(ors) if 'extra' in requirements: is_extra = True for _extras in requirements['extra']: for _, extra in _extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dependency) if not is_extra: package.requires.append(dependency) # Adding description package.description = release_info.get('summary', '') # Adding hashes information package.hashes = release_info['digests'] # Activate extra dependencies for extra in extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] self._packages.append(package) return package
def get_package_from_directory( cls, directory, name=None): # type: (Path, Optional[str]) -> Package supports_poetry = False pyproject = directory.joinpath("pyproject.toml") if pyproject.exists(): pyproject = TomlFile(pyproject) pyproject_content = pyproject.read() supports_poetry = ("tool" in pyproject_content and "poetry" in pyproject_content["tool"]) if supports_poetry: poetry = Factory().create_poetry(directory) pkg = poetry.package package = Package(pkg.name, pkg.version) for dep in pkg.requires: if not dep.is_optional(): package.requires.append(dep) for extra, deps in pkg.extras.items(): if extra not in package.extras: package.extras[extra] = [] for dep in deps: package.extras[extra].append(dep) package.python_versions = pkg.python_versions else: # Execute egg_info current_dir = os.getcwd() os.chdir(str(directory)) try: cwd = directory venv = EnvManager().get(cwd) venv.run("python", "setup.py", "egg_info") except EnvCommandError: result = SetupReader.read_from_directory(directory) if not result["name"]: # The name could not be determined # We use the dependency name result["name"] = name if not result["version"]: # The version could not be determined # so we raise an error since it is mandatory raise RuntimeError( "Unable to retrieve the package version for {}".format( directory)) package_name = result["name"] package_version = result["version"] python_requires = result["python_requires"] if python_requires is None: python_requires = "*" package_summary = "" requires = "" for dep in result["install_requires"]: requires += dep + "\n" if result["extras_require"]: requires += "\n" for extra_name, deps in result["extras_require"].items(): requires += "[{}]\n".format(extra_name) for dep in deps: requires += dep + "\n" requires += "\n" reqs = parse_requires(requires) else: os.chdir(current_dir) # Sometimes pathlib will fail on recursive # symbolic links, so we need to workaround it # and use the glob module instead. # Note that this does not happen with pathlib2 # so it's safe to use it for Python < 3.4. if PY35: egg_info = next( Path(p) for p in glob.glob( os.path.join(str(directory), "**", "*.egg-info"), recursive=True, )) else: egg_info = next(directory.glob("**/*.egg-info")) meta = pkginfo.UnpackedSDist(str(egg_info)) package_name = meta.name package_version = meta.version package_summary = meta.summary python_requires = meta.requires_python if meta.requires_dist: reqs = list(meta.requires_dist) else: reqs = [] requires = egg_info / "requires.txt" if requires.exists(): with requires.open(encoding="utf-8") as f: reqs = parse_requires(f.read()) finally: os.chdir(current_dir) package = Package(package_name, package_version) package.description = package_summary for req in reqs: dep = dependency_from_pep_508(req) if dep.in_extras: for extra in dep.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dep) if not dep.is_optional(): package.requires.append(dep) if python_requires: package.python_versions = python_requires if name and name != package.name: # For now, the dependency's name must match the actual package's name raise RuntimeError( "The dependency name for {} does not match the actual package's name: {}" .format(name, package.name)) package.source_type = "directory" package.source_url = directory.as_posix() return package
def package( self, name, # type: str version, # type: str extras=None # type: (Union[list, None]) ): # type: (...) -> Union[Package, None] try: index = self._packages.index(Package(name, version, version)) return self._packages[index] except ValueError: if extras is None: extras = [] release_info = self.get_release_info(name, version) if (self._fallback and release_info['requires_dist'] is None and not release_info['requires_python'] and not release_info['platform']): # No dependencies set (along with other information) # This might be due to actually no dependencies # or badly set metadata when uploading # So, we return None so that the fallback repository # can pick up more accurate info return package = Package(name, version, version) requires_dist = release_info['requires_dist'] or [] for req in requires_dist: try: dependency = dependency_from_pep_508(req) except InvalidMarker: # Invalid marker # We strip the markers hoping for the best req = req.split(';')[0] dependency = dependency_from_pep_508(req) except ValueError: # Likely unable to parse constraint so we skip it continue if dependency.extras: for extra in dependency.extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dependency) if not dependency.is_optional(): package.requires.append(dependency) # Adding description package.description = release_info.get('summary', '') # Adding hashes information package.hashes = release_info['digests'] # Activate extra dependencies for extra in extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] self._packages.append(package) return package
def search_for_directory( self, dependency): # type: (DirectoryDependency) -> List[Package] if dependency.supports_poetry(): from poetry.poetry import Poetry poetry = Poetry.create(dependency.full_path) pkg = poetry.package package = Package(pkg.name, pkg.version) for dep in pkg.requires: if not dep.is_optional(): package.requires.append(dep) for extra, deps in pkg.extras.items(): if extra not in package.extras: package.extras[extra] = [] for dep in deps: package.extras[extra].append(dep) package.python_versions = pkg.python_versions else: # Execute egg_info current_dir = os.getcwd() os.chdir(str(dependency.full_path)) try: cwd = dependency.full_path venv = Env.get(NullIO(), cwd=cwd) venv.run("python", "setup.py", "egg_info") except EnvCommandError: result = SetupReader.read_from_directory(dependency.full_path) if not result["name"]: # The name could not be determined # We use the dependency name result["name"] = dependency.name if not result["version"]: # The version could not be determined # so we raise an error since it is mandatory raise RuntimeError( "Unable to retrieve the package version for {}".format( dependency.path)) package_name = result["name"] package_version = result["version"] python_requires = result["python_requires"] if python_requires is None: python_requires = "*" package_summary = "" requires = "" for dep in result["install_requires"]: requires += dep + "\n" if result["extras_require"]: requires += "\n" for extra_name, deps in result["extras_require"].items(): requires += "[{}]\n".format(extra_name) for dep in deps: requires += dep + "\n" requires += "\n" reqs = parse_requires(requires) else: os.chdir(current_dir) # Sometimes pathlib will fail on recursive # symbolic links, so we need to workaround it # and use the glob module instead. # Note that this does not happen with pathlib2 # so it's safe to use it for Python < 3.4. if PY35: egg_info = next( Path(p) for p in glob.glob( os.path.join(str(dependency.full_path), "**", "*.egg-info"), recursive=True, )) else: egg_info = next(dependency.full_path.glob("**/*.egg-info")) meta = pkginfo.UnpackedSDist(str(egg_info)) package_name = meta.name package_version = meta.version package_summary = meta.summary python_requires = meta.requires_python if meta.requires_dist: reqs = list(meta.requires_dist) else: reqs = [] requires = egg_info / "requires.txt" if requires.exists(): with requires.open() as f: reqs = parse_requires(f.read()) finally: os.chdir(current_dir) package = Package(package_name, package_version) if dependency.name != package.name: # For now, the dependency's name must match the actual package's name raise RuntimeError( "The dependency name for {} does not match the actual package's name: {}" .format(dependency.name, package.name)) package.description = package_summary for req in reqs: dep = dependency_from_pep_508(req) if dep.in_extras: for extra in dep.in_extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dep) if not dep.is_optional(): package.requires.append(dep) if python_requires: package.python_versions = python_requires package.source_type = "directory" package.source_url = dependency.path.as_posix() for extra in dependency.extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] return [package]
def package(self, name, # type: str version, # type: str extras=None # type: (Union[list, None]) ): # type: (...) -> Union[Package, None] try: index = self._packages.index(Package(name, version, version)) return self._packages[index] except ValueError: if extras is None: extras = [] release_info = self.get_release_info(name, version) if ( self._fallback and release_info['requires_dist'] is None and not release_info['requires_python'] and '_fallback' not in release_info ): # Force cache update self._log( 'No dependencies found, downloading archives', level='debug' ) self._cache.forget('{}:{}'.format(name, version)) release_info = self.get_release_info(name, version) package = Package(name, version, version) requires_dist = release_info['requires_dist'] or [] for req in requires_dist: try: dependency = dependency_from_pep_508(req) except InvalidMarker: # Invalid marker # We strip the markers hoping for the best req = req.split(';')[0] dependency = dependency_from_pep_508(req) except ValueError: # Likely unable to parse constraint so we skip it self._log( 'Invalid constraint ({}) found in {}-{} dependencies, ' 'skipping'.format( req, package.name, package.version ), level='debug' ) continue if dependency.extras: for extra in dependency.extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dependency) if not dependency.is_optional(): package.requires.append(dependency) # Adding description package.description = release_info.get('summary', '') if release_info['requires_python']: package.python_versions = release_info['requires_python'] if release_info['platform']: package.platform = release_info['platform'] # Adding hashes information package.hashes = release_info['digests'] # Activate extra dependencies for extra in extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] self._packages.append(package) return package
def package( self, name, # type: str version, # type: str extras=None, # type: (Union[list, None]) ): # type: (...) -> Union[Package, None] if extras is None: extras = [] release_info = self.get_release_info(name, version) package = Package(name, version, version) requires_dist = release_info["requires_dist"] or [] for req in requires_dist: try: dependency = dependency_from_pep_508(req) except InvalidMarker: # Invalid marker # We strip the markers hoping for the best req = req.split(";")[0] dependency = dependency_from_pep_508(req) except ValueError: # Likely unable to parse constraint so we skip it self._log( "Invalid constraint ({}) found in {}-{} dependencies, " "skipping".format(req, package.name, package.version), level="debug", ) continue if dependency.extras: for extra in dependency.extras: if extra not in package.extras: package.extras[extra] = [] package.extras[extra].append(dependency) if not dependency.is_optional(): package.requires.append(dependency) # Adding description package.description = release_info.get("summary", "") if release_info["requires_python"]: package.python_versions = release_info["requires_python"] if release_info["platform"]: package.platform = release_info["platform"] # Adding hashes information package.hashes = release_info["digests"] # Activate extra dependencies for extra in extras: if extra in package.extras: for dep in package.extras[extra]: dep.activate() package.requires += package.extras[extra] return package