def test_can_set_buildtime_dependency(package_a: Requirement,
                                      package_b: Requirement,
                                      dependency_graph: DependencyGraph):
    dependency_graph.set_buildtime_dependency(dependent=package_a,
                                              dependency=package_b)
    assert dependency_graph.is_buildtime_dependency(dependent=package_a,
                                                    dependency=package_b)
def test_cyclic_runtime_dependencies_not_allowed(
        package_a: Requirement, package_b: Requirement,
        dependency_graph: DependencyGraph):
    dependency_graph.set_runtime_dependency(dependent=package_a,
                                            dependency=package_b)
    with pytest.raises(CyclicDependencyOccured):
        dependency_graph.set_runtime_dependency(dependent=package_b,
                                                dependency=package_a)
def test_can_detect_external_dependencies_for_packages(
    package_a: Requirement,
    external_dependency_a: ExternalDependency,
    dependency_graph: DependencyGraph,
):
    dependency_graph.set_external_dependency(dependent=package_a,
                                             dependency=external_dependency_a)
    assert dependency_graph.get_all_external_dependencies(package_a) == {
        external_dependency_a,
    }
def test_cannot_add_circular_buildtime_dependencies(
    package_a: Requirement,
    package_b: Requirement,
    dependency_graph: DependencyGraph,
):
    dependency_graph.set_buildtime_dependency(dependent=package_a,
                                              dependency=package_b)
    with pytest.raises(CyclicDependencyOccured):
        dependency_graph.set_buildtime_dependency(dependent=package_b,
                                                  dependency=package_a)
def test_external_dependencies_from_graph_are_retrieved(
    requirement_parser: RequirementParser, ) -> None:
    dependency_graph = DependencyGraph()
    requirement = requirement_parser.parse("testpackage")
    external_dependency = ExternalDependency("external")
    dependency_graph.set_external_dependency(dependent=requirement,
                                             dependency=external_dependency)
    retriever = RequirementDependencyRetriever(dependency_graph)
    assert external_dependency in retriever.get_external_dependency_for_requirement(
        requirement)
def test_build_time_dependencies_dont_show_up_as_runtime_dependencies(
    package_a: Requirement,
    package_b: Requirement,
    package_c: Requirement,
    dependency_graph: DependencyGraph,
):
    dependency_graph.set_runtime_dependency(dependent=package_a,
                                            dependency=package_b)
    dependency_graph.set_buildtime_dependency(dependent=package_b,
                                              dependency=package_c)
    assert not dependency_graph.is_runtime_dependency(dependent=package_a,
                                                      dependency=package_c)
def test_can_detect_indirect_runtime_dependencies(
    package_a: Requirement,
    package_b: Requirement,
    package_c: Requirement,
    dependency_graph: DependencyGraph,
) -> None:
    dependency_graph.set_runtime_dependency(dependent=package_a,
                                            dependency=package_b)
    dependency_graph.set_runtime_dependency(dependent=package_b,
                                            dependency=package_c)
    assert dependency_graph.is_runtime_dependency(dependent=package_a,
                                                  dependency=package_c)
def test_can_retrieve_external_dependencies_from_runtime_dependencies(
    package_a: Requirement,
    package_b: Requirement,
    external_dependency_a: ExternalDependency,
    dependency_graph: DependencyGraph,
):
    dependency_graph.set_runtime_dependency(dependent=package_a,
                                            dependency=package_b)
    dependency_graph.set_external_dependency(dependent=package_b,
                                             dependency=external_dependency_a)
    assert dependency_graph.get_all_external_dependencies(
        package=package_a) == {
            external_dependency_a,
        }
Exemple #9
0
def dependency_graph(
        draw,
        python_packages=lists(requirement(), unique_by=lambda x: x.name()),
        external_dependencies=lists(external_dependency()),
        is_runtime_dependency=booleans(),
        selections=integers(),
):
    graph = DependencyGraph()
    packages = draw(python_packages)
    if not packages:
        return graph
    for package in packages:
        index = draw(selections) % len(packages)
        try:
            if draw(is_runtime_dependency):
                graph.set_runtime_dependency(dependent=package,
                                             dependency=packages[index])
            else:
                graph.set_buildtime_dependency(dependent=package,
                                               dependency=packages[index])
        except CyclicDependencyOccured:
            continue
    for dependency in draw(external_dependencies):
        graph.set_external_dependency(dependent=packages[draw(selections) %
                                                         len(packages)],
                                      dependency=dependency)
    return graph
def test_can_retriev_all_runtime_dependency_names(
    package_a: Requirement,
    package_b: Requirement,
    package_c: Requirement,
    dependency_graph: DependencyGraph,
) -> None:
    dependency_graph.set_runtime_dependency(dependent=package_a,
                                            dependency=package_b)
    dependency_graph.set_runtime_dependency(dependent=package_b,
                                            dependency=package_c)
    assert dependency_graph.get_all_runtime_dependency_names(package_a) == {
        package_a.name(),
        package_b.name(),
        package_c.name(),
    }
 def check_dependency_graph(self, dependency_graph: DependencyGraph,
                            requirement_parser: RequirementParser):
     self.assertTrue(
         dependency_graph.is_runtime_dependency(
             requirement_parser.parse("django"),
             requirement_parser.parse("pytz"),
         ))
Exemple #12
0
def test_that_we_can_generate_an_empty_requirement_set_from_freshly_constructed_collector(
        current_platform, requirement_parser, logger: Logger,
        project_dir: str):
    collector = RequirementsCollector(current_platform, requirement_parser,
                                      logger, project_dir, DependencyGraph())
    requirements = collector.requirements()
    assert len(requirements) == 0
def collector(
    current_platform: TargetPlatform,
    requirement_parser: RequirementParser,
    logger: Logger,
    project_dir: str,
) -> RequirementsCollector:
    return RequirementsCollector(current_platform, requirement_parser, logger,
                                 project_dir, DependencyGraph())
def test_can_add_two_dependencies_graphs_and_buildtime_dependencies_are_also_added(
    package_a: Requirement,
    package_b: Requirement,
    package_c: Requirement,
    dependency_graph: DependencyGraph,
):
    other_dependency_graph = copy(dependency_graph)
    dependency_graph.set_buildtime_dependency(dependent=package_a,
                                              dependency=package_b)
    other_dependency_graph.set_buildtime_dependency(dependent=package_b,
                                                    dependency=package_c)
    sum_graph = dependency_graph + other_dependency_graph
    assert not dependency_graph.is_buildtime_dependency(dependent=package_a,
                                                        dependency=package_c)
    assert not other_dependency_graph.is_buildtime_dependency(
        dependent=package_a, dependency=package_c)
    assert sum_graph.is_buildtime_dependency(dependent=package_a,
                                             dependency=package_c)
def test_can_retrieve_external_dependencies_after_adding_graphs(
    package_a: Requirement,
    package_b: Requirement,
    external_dependency_a: ExternalDependency,
    external_dependency_b: ExternalDependency,
    dependency_graph: DependencyGraph,
):
    other_dependency_graph = copy(dependency_graph)
    dependency_graph.set_external_dependency(dependent=package_a,
                                             dependency=external_dependency_a)
    dependency_graph.set_runtime_dependency(dependent=package_a,
                                            dependency=package_b)
    other_dependency_graph.set_external_dependency(
        dependent=package_b, dependency=external_dependency_b)
    sum_graph = dependency_graph + other_dependency_graph
    assert sum_graph.get_all_external_dependencies(package=package_a) == {
        external_dependency_a,
        external_dependency_b,
    }
Exemple #16
0
 def setup_requirements_collector(self) -> RequirementsCollector:
     setup_requirement_collector = RequirementsCollector(
         self.target_platform(),
         self.requirement_parser(),
         self.logger(),
         str(self.configuration.project_directory),
         DependencyGraph(),
     )
     for build_input in self.configuration.setup_requirements:
         setup_requirement_collector.add_line(build_input)
     return setup_requirement_collector
def test_can_understand_wheel_dependecies(
        current_platform: TargetPlatform,
        requirement_parser: RequirementParser):
    runtime_dependencies = RequirementSet(current_platform)
    runtime_dependency = requirement_parser.parse("runtime_dependency")
    runtime_dependencies.add(runtime_dependency)
    build_dependencies = RequirementSet(current_platform)
    build_dependency = requirement_parser.parse("build_dependency")
    build_dependencies.add(build_dependency)
    wheel = Wheel(
        name="testpackage",
        version="",
        deps=runtime_dependencies,
        target_platform=current_platform,
        license="",
        homepage="",
        description="",
        build_dependencies=build_dependencies,
    )
    requirement = requirement_parser.parse("testpackage")
    dependency_graph = DependencyGraph()
    dependency_graph.import_wheel(wheel, requirement_parser)

    assert dependency_graph.is_buildtime_dependency(requirement,
                                                    build_dependency)
    assert dependency_graph.is_runtime_dependency(requirement,
                                                  runtime_dependency)
Exemple #18
0
    def run(self) -> None:
        requirements = self.requirements_collector().requirements()
        self.logger().info("pypi2nix v{} running ...".format(pypi2nix_version))
        if not requirements:
            self.logger().info(
                "No requirements were specified.  Ending program.")
            return

        setup_requirements = self.setup_requirements_collector().requirements()
        requirements_name = os.path.join(self.configuration.target_directory,
                                         self.configuration.output_basename)

        sources = Sources()
        sources.update(setup_requirements.sources())
        sources.update(requirements.sources())
        sources.update(self.setup_requirements_collector().sources())
        sources.update(self.requirements_collector().sources())

        self.logger().info("Downloading wheels and creating wheelhouse ...")

        pip = NixPip(
            nix=self.nix(),
            project_directory=self.configuration.project_directory,
            extra_env=self.configuration.extra_environment,
            extra_build_inputs=self._extra_build_inputs(),
            wheels_cache=self.configuration.wheels_caches,
            target_platform=self.target_platform(),
            logger=self.logger(),
            requirement_parser=self.requirement_parser(),
        )
        wheel_builder = WheelBuilder(
            pip=pip,
            download_directory=self.configuration.project_directory /
            "downloads",
            lib_directory=self.configuration.project_directory / "lib",
            extracted_wheel_directory=self.configuration.project_directory /
            "extracted-wheels",
            wheel_directory=self.configuration.project_directory / "wheels",
            logger=self.logger(),
            requirement_parser=self.requirement_parser(),
            target_platform=self.target_platform(),
            base_dependency_graph=self.base_dependency_graph(),
        )
        wheels = wheel_builder.build(requirements=requirements,
                                     setup_requirements=setup_requirements)
        requirements_frozen = wheel_builder.get_frozen_requirements()
        source_distributions = wheel_builder.source_distributions

        self.logger().info("Extracting metadata from pypi.python.org ...")

        metadata_fetcher = MetadataFetcher(
            sources=sources,
            logger=self.logger(),
            requirement_parser=self.requirement_parser(),
            pypi=Pypi(logger=self.logger()),
        )

        packages_metadata = metadata_fetcher.main(
            wheel_paths=wheels,
            target_platform=self.target_platform(),
            source_distributions=source_distributions,
        )
        self.logger().info("Generating Nix expressions ...")

        renderers: List[ExpressionRenderer] = []
        renderers.append(
            RequirementsRenderer(
                requirements_name=requirements_name,
                extra_build_inputs=self.extra_build_inputs(),
                python_version=self.configuration.python_version,
                target_directory=self.configuration.target_directory,
                logger=self.logger(),
                common_overrides=self.configuration.overrides,
                target_platform=self.target_platform(),
                requirements_frozen=requirements_frozen,
                code_formatter=self.code_formatter(),
            ))
        renderers.append(
            FlakeRenderer(
                target_path=Path(self.configuration.target_directory) /
                "flake.nix",
                target_platform=self.target_platform(),
                logger=self.logger(),
                overrides=self.configuration.overrides,
                extra_build_inputs=self.extra_build_inputs(),
                code_formatter=self.code_formatter(),
            ))
        for renderer in renderers:
            renderer.render_expression(
                packages_metadata=packages_metadata,
                sources=sources,
            )

        if self.configuration.dependency_graph_output_location:
            dependency_graph = DependencyGraph()
            for wheel in packages_metadata:
                dependency_graph.import_wheel(wheel, self.requirement_parser())
            with open(str(self.configuration.dependency_graph_output_location),
                      "w") as output_file:
                output_file.write(dependency_graph.serialize())
        self.print_user_information()
Exemple #19
0
 def _read_dependency_graph(self) -> DependencyGraph:
     with open(self._dependency_graph_output_path()) as f:
         return DependencyGraph.deserialize(f.read())
Exemple #20
0
def base_dependency_graph() -> DependencyGraph:
    return DependencyGraph()
Exemple #21
0
def collector(current_platform, requirement_parser, logger: Logger,
              project_dir: str):
    return RequirementsCollector(current_platform, requirement_parser, logger,
                                 project_dir, DependencyGraph())
def test_no_external_dependency_for_empty_dependency_graph(
    requirement_parser: RequirementParser, ) -> None:
    dependency_graph = DependencyGraph()
    retriever = RequirementDependencyRetriever(dependency_graph)
    requirement = requirement_parser.parse("testpackage")
    assert not retriever.get_external_dependency_for_requirement(requirement)
Exemple #23
0
def test_serialization_and_deserialization_leads_to_identity(
    dependency_graph: DependencyGraph, ):
    assert DependencyGraph.deserialize(
        dependency_graph.serialize()) == dependency_graph
Exemple #24
0
def test_equality_of_empty_graphs():
    assert DependencyGraph() == DependencyGraph()
Exemple #25
0
def main(
    version: str,
    verbose: int,
    quiet: int,
    nix_shell: Optional[str],
    nix_path: List[str],
    basename: str,
    extra_build_inputs: List[str],
    emit_extra_build_inputs: bool,
    extra_env: str,
    enable_tests: bool,
    python_version_argument: str,
    requirements: List[str],
    editable: List[str],
    setup_requires: List[str],
    overrides: List[NetworkFile],
    default_overrides: bool,
    wheels_cache: List[str],
    build_directory: Optional[str],
    dependency_graph_output: Optional[str],
    dependency_graph_input: Optional[NetworkFile],
) -> None:
    overrides_list: List[Overrides] = []
    if version:
        click.echo(pypi2nix_version)
        exit(0)
    verbosity = verbosity_from_int(verbose - quiet + DEFAULT_VERBOSITY)
    nix_executable_directory: Optional[str]
    if nix_shell is None:
        nix_executable_directory = None
    else:
        if not os.path.isfile(nix_shell):
            raise click.exceptions.UsageError(
                f"Specified `nix-shell` executable `{nix_shell}` does not exist."
            )
        else:
            nix_executable_directory = os.path.dirname(
                os.path.abspath(nix_shell))
    overrides_list += [
        OverridesNetworkFile(network_file) for network_file in overrides
    ]
    if default_overrides:
        overrides_list += tuple([
            OverridesGithub(
                owner="nix-community",
                repo="pypi2nix-overrides",
                path="overrides.nix",
            )
        ])
    python_version = getattr(PythonVersion, python_version_argument, None)
    if python_version is None:
        raise click.exceptions.UsageError(
            f"Python version `{python_version_argument}` not available")

    project_directory_context: ProjectDirectory = (
        TemporaryProjectDirectory() if build_directory is None else
        PersistentProjectDirectory(path=build_directory))
    if dependency_graph_input:
        dependency_graph = DependencyGraph.deserialize(
            dependency_graph_input.fetch())
    else:
        dependency_graph = DependencyGraph()
    with project_directory_context as _project_directory:
        configuration = ApplicationConfiguration(
            emit_extra_build_inputs=emit_extra_build_inputs,
            enable_tests=enable_tests,
            extra_build_inputs=args_as_list(extra_build_inputs),
            extra_environment=extra_env,
            nix_executable_directory=nix_executable_directory,
            nix_path=nix_path,
            output_basename=basename,
            overrides=overrides_list,
            python_version=python_version,
            requirement_files=requirements,
            requirements=editable,
            setup_requirements=setup_requires,
            verbosity=verbosity,
            wheels_caches=wheels_cache,
            project_directory=_project_directory,
            target_directory=os.getcwd(),
            dependency_graph_output_location=Path(dependency_graph_output)
            if dependency_graph_output else None,
            dependency_graph_input=dependency_graph,
        )
        Pypi2nix(configuration).run()
def dependency_graph() -> DependencyGraph:
    return DependencyGraph()
Exemple #27
0
 def __init__(self, dependency_graph: DependencyGraph = DependencyGraph()):
     self._dependency_graph = dependency_graph