예제 #1
0
    def test_run_noop(self, context: Context, state: State, tf_name: str,
                      tf_version: str) -> None:
        """Test not removing scipy from a TensorFlow stack."""
        scipy_package_version = PackageVersion(
            name="scipy",
            version="==1.2.2",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )
        tf_package_version = PackageVersion(
            name=tf_name,
            version=f"=={tf_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        assert "tensorflow" not in state.resolved_dependencies
        state.resolved_dependencies[
            "tensorflow"] = tf_package_version.to_tuple()
        context.register_package_version(tf_package_version)
        context.dependents["scipy"] = {
            scipy_package_version.to_tuple():
            {(tf_package_version.to_tuple(), "rhel", "8", "3.6")}
        }

        unit = TensorFlowRemoveSciPyStep()
        with TensorFlowRemoveSciPyStep.assigned_context(context):
            assert unit.run(state, scipy_package_version) is None
예제 #2
0
    def test_get_package_version(self, context: Context,
                                 package_version: PackageVersion) -> None:
        """Test getting registering and getting a package version."""
        with pytest.raises(NotFound):
            context.get_package_version(package_version.to_tuple())

        assert context.register_package_version(package_version) is False
        assert context.get_package_version(
            package_version.to_tuple()) is package_version
예제 #3
0
    def _run_state_with_initiator(self, state: State,
                                  package_version: PackageVersion) -> bool:
        """Check state match respecting also initiator of the give package."""
        state_prescription = self.match_prescription.get("state")
        if not state_prescription:
            # Nothing to check.
            return True

        package_version_from = state_prescription.get(
            "package_version_from") or []
        # XXX: we explicitly do not consider runtime environment as we expect to have it only one here.
        dependents = {
            i[0]
            for i in self.context.dependents.get(package_version.name, {}).get(
                package_version.to_tuple(), set())
        }

        for resolved_dependency in package_version_from:
            resolved = state.resolved_dependencies.get(
                resolved_dependency["name"])
            if not resolved:
                return False

            if not self._check_package_tuple_from_prescription(
                    resolved, resolved_dependency):
                return False

            if resolved not in dependents:
                _LOGGER.debug(
                    "Package %r stated in package_version_from not a did not introduce package %r",
                    resolved,
                    package_version.to_tuple(),
                )
                return False

            dependents.discard(resolved)

        if dependents and not state_prescription.get(
                "package_version_from_allow_other", False):
            for dependent in dependents:
                if dependent == state.resolved_dependencies.get(dependent[0]):
                    return False

        for resolved_dependency in state_prescription.get(
                "resolved_dependencies", []):
            resolved = state.resolved_dependencies.get(
                resolved_dependency["name"])
            if not resolved:
                return False

            if not self._check_package_tuple_from_prescription(
                    resolved, resolved_dependency):
                return False

        return True
예제 #4
0
    def test_not_fully_resolved_error(self):
        """Test trying to running pipeline with unresolved package produces an error."""
        project = Project.from_strings(_PIPFILE_STR)
        pipeline = Pipeline(
            graph=None,  # We avoid low-level testing down to thoth-storages.
            project=project,
            sieves=[],
            steps=[],
            strides=[],
        )

        direct_dependency = PackageVersion(
            name="flask",
            version="==1.0.2",
            index=Source("https://pypi.org/simple"),
            develop=False,
        )

        step_context = StepContext.from_paths(
            {direct_dependency.to_tuple(): direct_dependency},
            {direct_dependency.to_tuple(): [
                (("flask", "1.0.2", "https://pypi.org/simple"), ("werkzeug", None, None))
            ]},
        )

        flexmock(
            pipeline,
            _prepare_direct_dependencies=lambda with_devel: [direct_dependency],
            _resolve_transitive_dependencies=lambda _: step_context,
        )

        with pytest.raises(NotResolvedError):
            pipeline.conduct(limit=None, count=None)

        # Try again, now with first item in the tuple list - same error should be produced.
        step_context = StepContext.from_paths(
            {direct_dependency.to_tuple(): direct_dependency},
            {direct_dependency.to_tuple(): [
                (("flask", None, None), ("werkzeug", "0.15.6", "https://pypi.org/simple"))
            ]},
        )

        flexmock(
            pipeline,
            _prepare_direct_dependencies=lambda with_devel: [direct_dependency],
            _resolve_transitive_dependencies=lambda _: step_context,
        )

        with pytest.raises(NotResolvedError):
            pipeline.conduct(limit=None, count=None)
예제 #5
0
    def test_get_package_version_graceful(
            self, context: Context, package_version: PackageVersion) -> None:
        """Test getting registered package version, gracefully."""
        assert context.get_package_version(package_version.to_tuple(),
                                           graceful=True) is None
        with pytest.raises(NotFound):
            context.get_package_version(package_version.to_tuple(),
                                        graceful=False)

        assert context.register_package_version(package_version) is False

        assert context.get_package_version(package_version.to_tuple(),
                                           graceful=True) is package_version
        assert context.get_package_version(package_version.to_tuple(),
                                           graceful=False) is package_version
예제 #6
0
    def test_no_tf_21(self, urllib3_version: str, tf_version: str) -> None:
        """Test no penalization for TensorFlow other than 2.1 by this pipeline step."""
        urllib3_package_version = PackageVersion(
            name="urllib3",
            version=f"=={urllib3_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        tf_package_version = PackageVersion(
            name="tensorflow",
            version=f"=={tf_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        state = State()
        state.resolved_dependencies[
            "tensorflow"] = tf_package_version.to_tuple()

        # Context is not used during the actual pipeline run.
        context = flexmock()
        with TensorFlow21Urllib3Step.assigned_context(context):
            unit = TensorFlow21Urllib3Step()
            assert unit.run(state, urllib3_package_version) is None
예제 #7
0
파일: cve.py 프로젝트: CermakM/adviser
    def run(
        self, _: State, package_version: PackageVersion
    ) -> Optional[Tuple[float, List[Dict[str, str]]]]:
        """Penalize stacks with a CVE."""
        try:
            cve_records = self.context.graph.get_python_cve_records_all(
                package_name=package_version.name,
                package_version=package_version.locked_version,
            )
        except NotFoundError as exc:
            _LOGGER.warning("Package %r in version %r not found: %r", str(exc))
            return None

        if cve_records:
            _LOGGER.debug(
                "Found a CVEs for %r: %r", package_version.to_tuple(), cve_records
            )
            penalization = len(cve_records) * self.configuration["cve_penalization"]

            # Note down package causing this CVE.
            for record in cve_records:
                record["package_name"] = package_version.name

            return penalization, cve_records

        return None
예제 #8
0
    def run(
        self, state: State, package_version: PackageVersion
    ) -> Optional[Tuple[Optional[float], Optional[List[Dict[str, str]]]]]:
        """Remove SciPy dependency from a TensorFlow>2.1<=2.3 stack."""
        tensorflow_any = (
            state.resolved_dependencies.get("tensorflow")
            or state.resolved_dependencies.get("tensorflow-cpu")
            or state.resolved_dependencies.get("tensorflow-gpu")
        )

        if not tensorflow_any:
            return None

        tf_package_version = self.context.get_package_version(tensorflow_any)
        if not tf_package_version:
            return None

        tf_release = tf_package_version.semantic_version.release[:2]
        if tf_release < (2, 1) or tf_release >= (2, 3):
            return None

        # Now check what package introduced the SciPy dependency. If it is solely TensorFlow, we can
        # safely remove SciPy from dependencies.
        scipy_dependents = {i[0] for i in self.context.dependents["scipy"][package_version.to_tuple()]}
        introduced_by = scipy_dependents & set(state.resolved_dependencies.values())
        if len(introduced_by) == 1 and next(iter(introduced_by)) == tensorflow_any:
            if not self._message_logged:
                self._message_logged = True
                _LOGGER.warning("%s - see %s", self._MESSAGE, self._LINK)
                self.context.stack_info.append({"type": "WARNING", "message": self._MESSAGE, "link": self._LINK})

            raise SkipPackage

        return None
예제 #9
0
    def test_run_not_acceptable(self, context: Context, tf_name: str,
                                tf_version: str, np_version: str) -> None:
        """Test resolutions that are not acceptable."""
        package_version = PackageVersion(
            name="numpy",
            version=f"=={np_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        tf_package_version = PackageVersion(
            name=tf_name,
            version=f"=={tf_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        state = State()
        state.add_resolved_dependency(tf_package_version.to_tuple())
        context.register_package_version(tf_package_version)

        unit = TensorFlow22NumPyStep()
        unit.pre_run()

        with unit.assigned_context(context):
            assert unit._message_logged is False
            with pytest.raises(NotAcceptable):
                unit.run(state, package_version)

        assert unit._message_logged is True
예제 #10
0
    def test_tf_21(self, context: Context, urllib3_version: str,
                   tf_version: str) -> None:
        """Test penalizing TensorFlow in version 2.1."""
        tf_package_version = PackageVersion(
            name="tensorflow",
            version=f"=={tf_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        urllib3_package_version = PackageVersion(
            name="urllib3",
            version=f"=={urllib3_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        state = State()
        state.resolved_dependencies[
            "tensorflow"] = tf_package_version.to_tuple()

        assert not context.stack_info

        with TensorFlow21Urllib3Step.assigned_context(context):
            unit = TensorFlow21Urllib3Step()
            unit.pre_run()
            assert unit._message_logged is False
            with pytest.raises(NotAcceptable):
                assert unit.run(state, urllib3_package_version)
                assert unit._message_logged is True

        assert context.stack_info
        assert self.verify_justification_schema(context.stack_info)
예제 #11
0
    def test_run_noop(self, context: Context, tf_name: str, tf_version: str,
                      gast_version: str) -> None:
        """Test no operation performed when not invalid combination is seen."""
        gast_package_version = PackageVersion(
            name="gast",
            version=f"=={gast_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )
        tf_package_version = PackageVersion(
            name=tf_name,
            version=f"=={tf_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        state = State()
        state.add_resolved_dependency(tf_package_version.to_tuple())
        context.register_package_version(tf_package_version)

        unit = TensorFlow114GastStep()

        with unit.assigned_context(context):
            assert unit._message_logged is False
            assert unit.run(state, gast_package_version) is None
            assert unit._message_logged is False
예제 #12
0
 def test_register_package_version_existing(
         self, context: Context, package_version: PackageVersion) -> None:
     """Test registering an existing package version to context."""
     assert context.register_package_version(package_version) is False
     assert context.get_package_version(
         package_version.to_tuple()) is package_version
     assert context.register_package_version(package_version) is True
예제 #13
0
    def test_tf_21(self, context: Context, tf_version: str, h5py_version: str) -> None:
        """Test blocking resolution of h5py with TensorFlow==2.1 or TensorFlow==2.3.1."""
        tf_package_version = PackageVersion(
            name="tensorflow",
            version=f"=={tf_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        h5py_package_version = PackageVersion(
            name="h5py",
            version=f"=={h5py_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        state = State()
        state.resolved_dependencies["tensorflow"] = tf_package_version.to_tuple()
        context.register_package_version(tf_package_version)

        assert not context.stack_info

        with self.UNIT_TESTED.assigned_context(context):
            unit = self.UNIT_TESTED()
            unit.pre_run()
            assert unit._message_logged is False
            with pytest.raises(NotAcceptable):
                unit.run(state, h5py_package_version)
            assert unit._message_logged is True

        assert context.stack_info
        assert self.verify_justification_schema(context.stack_info)
예제 #14
0
    def test_run_not_acceptable(self, context: Context, tf_name: str,
                                tf_version: str, gast_version: str) -> None:
        """Test not acceptable TensorFlow<=1.14 with gast>0.2.2."""
        gast_package_version = PackageVersion(
            name="gast",
            version=f"=={gast_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )
        tf_package_version = PackageVersion(
            name=tf_name,
            version=f"=={tf_version}",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        state = State()
        state.add_resolved_dependency(tf_package_version.to_tuple())
        context.register_package_version(tf_package_version)

        unit = TensorFlow114GastStep()

        with unit.assigned_context(context):
            assert unit._message_logged is False
            with pytest.raises(NotAcceptable):
                unit.run(state, gast_package_version)

        assert unit._message_logged is True
예제 #15
0
    def test_stride_remove_stack(self):
        project = Project.from_strings(_PIPFILE_STR)

        direct_dependency = PackageVersion(
            name="flask",
            version="==1.0.2",
            index=Source("https://pypi.org/simple"),
            develop=False,
        )

        step_context = StepContext.from_paths(
            {direct_dependency.to_tuple(): direct_dependency},
            {direct_dependency.to_tuple(): []},
        )

        pipeline = Pipeline(
            graph=None,  # We avoid low-level testing down to thoth-storages.
            project=project,
            sieves=[],
            steps=[],
            strides=[
                (_MockStrideRemoveStack, None)
            ],
        )

        flexmock(
            pipeline,
            _prepare_direct_dependencies=lambda with_devel: [direct_dependency],
            _resolve_transitive_dependencies=lambda _: step_context,
        )

        # We raise an exception on first walk call, no stacks should be produced.
        pipeline_products = list(pipeline.conduct(limit=None, count=None))
        assert len(pipeline_products) == 0
예제 #16
0
    def run(
        self, _: State, package_version: PackageVersion
    ) -> Optional[Tuple[float, List[Dict[str, str]]]]:
        """Penalize stacks with a CVE."""
        try:
            cve_records = self.context.graph.get_python_cve_records_all(
                package_name=package_version.name,
                package_version=package_version.locked_version,
            )
        except NotFoundError as exc:
            _LOGGER.warning("Package %r in version %r not found: %r", str(exc))
            return None

        if cve_records:
            package_version_tuple = package_version.to_tuple()
            _LOGGER.debug("Found a CVEs for %r: %r", package_version_tuple,
                          cve_records)

            if self.context.recommendation_type == RecommendationType.SECURITY:
                if package_version_tuple not in self._messages_logged:
                    self._messages_logged.add(package_version_tuple)
                    for cve_record in cve_records:
                        message = (
                            f"Skipping including package {package_version_tuple!r} as a CVE "
                            f"{cve_record['cve_id']!r} was found")
                        _LOGGER.warning(
                            "%s: %s",
                            message,
                            cve_record["details"],
                        )

                        self.context.stack_info.append({
                            "type":
                            "WARNING",
                            "message":
                            message,
                            "link":
                            self._JUSTIFICATION_LINK
                        })

                raise NotAcceptable

            penalization = len(
                cve_records) * self.configuration["cve_penalization"]

            justification = []
            for cve_record in cve_records:
                message = f"Package  {package_version_tuple!r} has a CVE {cve_record['cve_id']!r}"
                justification.append({
                    "package_name": package_version.name,
                    "link": self._JUSTIFICATION_LINK,
                    "advisory": cve_record["details"],
                    "message": message,
                    "type": "WARNING",
                })

            return max(penalization, -1.0), justification

        return None
예제 #17
0
    def test_run_develop(self, context: Context, state: State,
                         develop: bool) -> None:
        """Test running this pipeline unit resulting in a justification addition when "not" index url is used."""
        prescription_str = f"""
name: GHReleaseNotes
type: wrap.GHReleaseNotes
should_include:
  adviser_pipeline: true
match:
  state:
    resolved_dependencies:
      name: thoth-solver
      develop: {'true' if develop else 'false'}
run:
  release_notes:
    organization: thoth-station
    repository: solver
    tag_version_prefix: v
"""
        units = list(self._instantiate_gh_release_notes_wrap(prescription_str))
        assert len(
            units
        ) == 1, "Multiple units created, expected only one based on prescription"
        unit = units[0]

        state.resolved_dependencies.clear()
        state.justification.clear()

        package_version = PackageVersion(
            name="thoth-solver",
            version="==0.5.0",
            index=Source("https://pypi.org/simple"),
            develop=develop,
        )
        state.add_resolved_dependency(package_version.to_tuple())
        context.register_package_version(package_version)

        unit.pre_run()
        with unit.assigned_context(context):
            # Run twice to verify the justification is added just once.
            assert unit.run(state) is None
            assert unit.run(state) is None

        self.verify_justification_schema(state.justification)
        assert set(tuple(i.items()) for i in state.justification) == {
            (
                ("type", "INFO"),
                ("message", "Release notes for package 'thoth-solver'"),
                ("link",
                 "https://github.com/thoth-station/solver/releases/tag/v0.5.0"
                 ),
                ("package_name", "thoth-solver"),
            ),
        }
예제 #18
0
    def register_package_version(self, package_version: PackageVersion) -> bool:
        """Register the given package version to the context."""
        package_tuple = package_version.to_tuple()
        registered = self.package_versions.get(package_tuple)
        if registered:
            # If the given package is shared in develop and in the main part, make it main stack part.
            registered.develop = registered.develop or package_version.develop
            return True

        # Direct dependency, no dependency introduced this one.
        self._note_dependencies(package_tuple=None, dependency_tuple=package_tuple)
        self.package_versions[package_tuple] = package_version
        return False
예제 #19
0
 def run(
     self, _: State, package_version: PackageVersion
 ) -> Optional[Tuple[Optional[float], Optional[List[Dict[str, str]]]]]:
     """Score the given package regardless of the state."""
     # Using seed set to process on the adviser run affects this call - so adviser
     # with same seed set shared scores generated across runs.
     score = self._score_history.setdefault(
         package_version.to_tuple(),
         random.uniform(self.SCORE_MIN, self.SCORE_MAX)
         if random.random() <= self.configuration["assign_probability"] else
         0.0,
     )
     return score, None
    def test_run(self) -> None:
        """Test computing package combinations."""
        pypi = Source("https://pypi.org/simple")
        pv0 = PackageVersion(
            name="flask",
            version="==1.0.0",
            index=pypi,
            develop=False,
        )
        pv1 = PackageVersion(
            name="flask",
            version="==0.12",
            index=pypi,
            develop=False,
        )
        pv2 = PackageVersion(
            name="pandas",
            version="==1.3.3",
            index=pypi,
            develop=False,
        )
        pv3 = PackageVersion(
            name="pandas",
            version="==1.0.0",
            index=pypi,
            develop=False,
        )

        unit = self.UNIT_TESTED()
        unit.update_configuration({
            "package_name":
            None,
            "package_combinations": ["flask", "werkzeug"],
        })
        unit.unit_run = True
        unit.pre_run()

        assert unit.unit_run is False, "Parent pre_run was probably not called"

        assert list(unit.run((pv for pv in (pv0, )))) == [pv0]
        assert list(unit.run((pv for pv in (pv1, )))) == [pv1]
        assert list(unit.run((pv for pv in (pv2, )))) == [pv2]
        assert list(unit.run((pv for pv in (pv3, )))) == []
        assert list(unit.run((pv for pv in (pv2, )))) == [pv2]
        assert list(unit.run((pv for pv in (pv1, )))) == [pv1]
        assert list(unit.run((pv for pv in (pv0, )))) == [pv0]

        assert unit._package_combinations == {"flask", "werkzeug"}
        assert unit._package_tuples_seen == {
            "pandas": pv2.to_tuple(),
        }
예제 #21
0
파일: cve.py 프로젝트: fridex/adviser
    def run(
        self, _: State, package_version: PackageVersion
    ) -> Optional[Tuple[float, List[Dict[str, str]]]]:
        """Penalize stacks with a CVE."""
        try:
            cve_records = self.context.graph.get_python_cve_records_all(
                package_name=package_version.name,
                package_version=package_version.locked_version,
            )
        except NotFoundError as exc:
            _LOGGER.warning("Package %r in version %r not found: %r", exc)
            return None

        if cve_records:
            package_version_tuple = package_version.to_tuple()
            _LOGGER.debug("Found a CVEs for %r: %r", package_version_tuple,
                          cve_records)

            justification = []
            for cve_record in cve_records:
                message = f"Package  {package_version_tuple!r} has a CVE {cve_record['cve_id']!r}"
                justification.append({
                    "package_name": package_version.name,
                    "link": cve_record.get("link") or self._JUSTIFICATION_LINK,
                    "advisory": cve_record["details"],
                    "message": message,
                    "type": "WARNING",
                })

            if self.context.recommendation_type not in (
                    RecommendationType.LATEST, RecommendationType.TESTING):
                # Penalize only if not latest/testing.
                penalization = len(
                    cve_records) * self.configuration["cve_penalization"]
                return max(penalization, -1.0), justification

            return 0.0, justification
        else:
            justification = [{
                "package_name":
                package_version.name,
                "link":
                self._JUSTIFICATION_LINK_NO_CVE,
                "type":
                "INFO",
                "message":
                f"No known CVE known for {package_version.name!r} in "
                f"version {package_version.locked_version!r}",
            }]
            return 0.0, justification
예제 #22
0
 def _do_try_exclude(sieve_context: SieveContext,
                     package_version: PackageVersion, config: dict) -> None:
     """Try to exclude the given package, produce warning if exclusion was not successful."""
     try:
         sieve_context.remove_package(package_version)
     except CannotRemovePackage as exc:
         # TODO: this should go to sieve context and be reported to the user in final recommendations
         _LOGGER.warning(
             "Using package %r which was released for different operating system %r, package"
             "cannot be removed: %s",
             package_version.to_tuple(),
             config["os_version"],
             str(exc),
         )
예제 #23
0
    def run(
        self, _: State, package_version: PackageVersion
    ) -> Optional[Tuple[Optional[float], Optional[List[Dict[str, str]]]]]:
        """Score the given package."""
        package_tuple = package_version.to_tuple()
        score = self._history.get(package_tuple)

        if score is not None:
            return score, None

        idx = self._idx
        self._idx = (self._idx + 1) % self.configuration["buffer_size"]
        self._history[package_tuple] = self._buffer[idx]
        return self._buffer[idx], None
예제 #24
0
    def test_run_deps(self, context: Context, state: State) -> None:
        """Test not removing scipy from a TensorFlow stack if introduced by another dependency."""
        scipy_package_version = PackageVersion(
            name="scipy",
            version="==1.2.2",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )
        tf_package_version = PackageVersion(
            name="tensorflow",
            version="==2.2.0",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )
        another_package_version = PackageVersion(
            name="some-package",
            version="==1.0.0",
            develop=False,
            index=Source("https://pypi.org/simple"),
        )

        assert "tensorflow" not in state.resolved_dependencies
        state.resolved_dependencies[
            "tensorflow"] = tf_package_version.to_tuple()
        state.resolved_dependencies[
            another_package_version.name] = another_package_version.to_tuple()
        context.register_package_version(tf_package_version)
        context.dependents["scipy"] = {
            scipy_package_version.to_tuple(): {
                (tf_package_version.to_tuple(), "rhel", "8", "3.6"),
                (another_package_version.to_tuple(), "rhel", "8", "3.6"),
            }
        }

        unit = TensorFlowRemoveSciPyStep()
        with TensorFlowRemoveSciPyStep.assigned_context(context):
            assert unit.run(state, scipy_package_version) is None
예제 #25
0
    def run(
        self, package_version: PackageVersion
    ) -> Generator[Tuple[str, str, str], None, None]:
        """Run main entry-point for pseudonyms to map packages to their counterparts."""
        if (not self._index_url_check(
                self._index_url, package_version.index.url)) or (
                    self._specifier is not None
                    and package_version.locked_version not in self._specifier):
            yield from ()
            return None

        to_yield = self.run_prescription["yield"]
        to_yield_package_version = to_yield.get("package_version") or {}
        if to_yield.get("yield_matched_version"):
            pseudonym_package_version = package_version.locked_version
        else:
            pseudonym_package_version = to_yield_package_version.get(
                "locked_version")
            if pseudonym_package_version:
                pseudonym_package_version = pseudonym_package_version[2:]

        runtime_environment = self.context.project.runtime_environment
        pseudonyms = self.context.graph.get_solved_python_package_versions_all(
            package_name=to_yield_package_version.get("name"),
            package_version=pseudonym_package_version,
            index_url=to_yield_package_version.get("index_url"),
            count=None,
            os_name=runtime_environment.operating_system.name,
            os_version=runtime_environment.operating_system.version,
            python_version=runtime_environment.python_version,
            distinct=True,
            is_missing=False,
        )

        prescription_conf = self._configuration["prescription"]
        if pseudonyms and not prescription_conf["run"]:
            self._run_stack_info()
            self._run_log()
            prescription_conf["run"] = True

        for pseudonym in pseudonyms:
            _LOGGER.info(
                "%s: Considering package %r as a pseudonym of %r",
                self.get_unit_name(),
                pseudonym,
                package_version.to_tuple(),
            )
            yield pseudonym[0], pseudonym[1], pseudonym[2]
예제 #26
0
    def test_run_develop_state_match(self, context: Context, state: State,
                                     develop: bool,
                                     state_develop: bool) -> None:
        """Test not running the prescription if develop flag is set also on the state match."""
        prescription_str = f"""
name: StepUnit
type: step
should_include:
  times: 1
  adviser_pipeline: true
match:
  package_version:
    name: numpy
    develop: {'true' if develop else 'false'}
  state:
    resolved_dependencies:
    - name: pytest
      develop: {'true' if state_develop else 'false'}
run:
  score: 0.5
"""
        prescription = yaml.safe_load(prescription_str)
        PRESCRIPTION_STEP_SCHEMA(prescription)
        StepPrescription.set_prescription(prescription)
        package_version = PackageVersion(
            name="numpy",
            version="==1.19.1",
            index=Source("https://pypi.org/simple"),
            develop=develop,
        )

        state_package_version = PackageVersion(
            name="pytest",
            version="==6.2.4",
            index=Source("https://pypi.org/simple"),
            develop=state_develop,
        )
        state.add_resolved_dependency(state_package_version.to_tuple())
        context.register_package_version(state_package_version)

        unit = StepPrescription()
        unit.pre_run()
        with unit.assigned_context(context):
            result = unit.run(state, package_version)

        assert isinstance(result, tuple)
        assert result[0] == 0.5
        assert result[1] is None
예제 #27
0
    def test_conduct_premature_stream_end(self):
        """Test pipeline reports premature stream error if libdependency_graph.so died."""
        def raise_premature_stream_error():
            raise PrematureStreamEndError("Premature stream exception")

        project = Project.from_strings(_PIPFILE_STR)
        pipeline = Pipeline(
            graph=None,  # We avoid low-level testing down to thoth-storages.
            project=project,
            sieves=[],
            steps=[],
            strides=[],
        )

        flexmock(
            DependencyGraphWalker,
            walk=raise_premature_stream_error,
        )

        direct_dependency = PackageVersion(
            name="flask",
            version="==1.0.2",
            index=Source("https://pypi.org/simple"),
            develop=False,
        )

        step_context = StepContext.from_paths(
            {direct_dependency.to_tuple(): direct_dependency},
            {direct_dependency.to_tuple(): []},
        )

        flexmock(
            pipeline,
            _prepare_direct_dependencies=lambda with_devel: [direct_dependency],
            _resolve_transitive_dependencies=lambda _: step_context,
        )

        # We raise an exception on first walk call, no stacks should be produced.
        assert len(list(pipeline.conduct(limit=None, count=None))) == 0

        # Get stack info after conduct.
        stack_info = pipeline.get_stack_info()
        assert len(stack_info) == 1
        stack_info_entry = stack_info[0]
        assert "type" in stack_info_entry
        assert stack_info_entry["type"] == "WARNING"
        assert "justification" in stack_info_entry
예제 #28
0
    def test_stride_simple_run(self):
        """Test running a single stride inside pipeline."""
        project = Project.from_strings(_PIPFILE_STR)

        direct_dependency = PackageVersion(
            name="flask",
            version="==1.0.2",
            index=Source("https://pypi.org/simple"),
            develop=False,
        )

        step_context = StepContext.from_paths(
            {direct_dependency.to_tuple(): direct_dependency},
            {direct_dependency.to_tuple(): []}
        )

        pipeline = Pipeline(
            graph=None,  # We avoid low-level testing down to thoth-storages.
            project=project,
            sieves=[],
            steps=[
                (_MockStep, _MOCK_STEP_PARAMETERS)
            ],
            strides=[
                (_MockStride, _MOCK_STRIDE_PARAMETERS)
            ],
        )

        flexmock(
            pipeline,
            _prepare_direct_dependencies=lambda with_devel: [direct_dependency],
            _resolve_transitive_dependencies=lambda _: step_context,
        )

        # We raise an exception on first walk call, no stacks should be produced.
        pipeline_products = list(pipeline.conduct(limit=None, count=None))
        assert len(pipeline_products) == 1
        assert pipeline.get_stack_info() == []

        pipeline_product = pipeline_products[0]
        assert isinstance(pipeline_product, PipelineProduct)
        assert pipeline_product.justification == _MOCK_STRIDE_JUSTIFICATION
        assert pipeline_product.score == 1.0
        assert pipeline_product.project
예제 #29
0
    def test_run_match_develop(self, context: Context, state: State, develop: bool) -> None:
        """Test running this pipeline unit based on develop matching."""
        prescription_str = f"""
name: StrideUnit
type: stride
should_include:
  times: 1
  adviser_pipeline: true
match:
  state:
    resolved_dependencies:
      - name: flask
        develop: {'true' if develop else 'false'}
run:
  stack_info:
    - type: INFO
      message: This message will be shown
      link: https://thoth-station.ninja
"""
        prescription = yaml.safe_load(prescription_str)
        PRESCRIPTION_STRIDE_SCHEMA(prescription)
        StridePrescription.set_prescription(prescription)
        package_version = PackageVersion(
            name="flask",
            version="==2.0.1",
            index=Source("https://pypi.org/simple"),
            develop=develop,
        )
        state.add_resolved_dependency(package_version.to_tuple())
        context.register_package_version(package_version)

        assert not context.stack_info

        unit = StridePrescription()
        unit.pre_run()
        with unit.assigned_context(context):
            assert unit.run(state) is None

            # Run one more time to verify the stack info is added just once.
            assert unit.run(state) is None

        assert context.stack_info == [
            {"type": "INFO", "message": "This message will be shown", "link": "https://thoth-station.ninja"}
        ]
예제 #30
0
    def test_run_develop(self, context: Context, state: State,
                         develop: bool) -> None:
        """Test running this pipeline unit based on matching develop flag."""
        prescription_str = f"""
name: WrapUnit
type: wrap
should_include:
  times: 1
  adviser_pipeline: true
match:
  state:
    resolved_dependencies:
      - name: flask
        develop: {'true' if develop else 'false'}
run:
  justification:
    - type: INFO
      message: This message will be shown
      link: https://thoth-station.ninja
"""
        prescription = yaml.safe_load(prescription_str)
        PRESCRIPTION_WRAP_SCHEMA(prescription)
        WrapPrescription.set_prescription(prescription)

        package_version = PackageVersion(
            name="flask",
            version="==2.0.1",
            index=Source("https://pypi.org/simple"),
            develop=develop,
        )
        state.add_resolved_dependency(package_version.to_tuple())
        context.register_package_version(package_version)

        state.justification.clear()

        unit = WrapPrescription()
        unit.pre_run()
        with unit.assigned_context(context):
            assert unit.run(state) is None
            # Run one more time to verify justification is added only once.
            assert unit.run(state) is None

        assert state.justification == unit.run_prescription["justification"]