def find_candidates(
        self,
        requirement: Requirement,
        allow_prereleases: bool | None = None,
        ignore_requires_python: bool = False,
        minimal_version: bool = False,
    ) -> Iterable[Candidate]:
        """Find candidates of the given NamedRequirement. Let it to be implemented in
        subclasses.

        :param requirement: the requirement to find
        :param allow_prereleases: whether to include pre-releases
        :param ignore_requires_python: whether to ignore the requires-python marker
        :param minimal_version: whether to prefer the minimal versions of the package
        """
        # `allow_prereleases` is None means to let the specifier decide whether to
        # include prereleases
        from unearth.utils import LazySequence

        if self.is_this_package(requirement):
            return [self.make_this_candidate(requirement)]
        requires_python = requirement.requires_python & self.env_spec.requires_python
        cans = LazySequence(self._find_candidates(requirement, minimal_version=minimal_version))
        applicable_cans = LazySequence(
            c
            for c in cans
            if requirement.specifier.contains(c.version, allow_prereleases)  # type: ignore[arg-type, union-attr]
        )

        def filter_candidates_with_requires_python(candidates: Iterable[Candidate]) -> Generator[Candidate]:
            env_requires_python = PySpecSet(self.env_spec.requires_python)
            if ignore_requires_python:
                yield from candidates
                return

            def python_specifier(spec: str | PySpecSet) -> str:
                if isinstance(spec, PySpecSet):
                    spec = str(spec)
                return "all Python versions" if not spec else f"Python{spec}"

            for candidate in candidates:
                if not requires_python.is_subset(candidate.requires_python):
                    if self._should_ignore_package_warning(requirement):
                        continue
                    working_requires_python = env_requires_python & PySpecSet(candidate.requires_python)
                    if working_requires_python.is_empty():  # pragma: no cover
                        continue
                    warnings.warn(
                        f"Skipping {candidate.name}@{candidate.version} because it requires "
                        f"{python_specifier(candidate.requires_python)} but the lock targets to work with "
                        f"{python_specifier(env_requires_python)}. Instead, another version of "
                        f"{candidate.name} that supports {python_specifier(env_requires_python)} will "
                        f"be used.\nIf you want to install {candidate.name}@{candidate.version}, "
                        "narrow down the `requires-python` range to "
                        f'include this version. For example, "{working_requires_python}" should work.',
                        PackageWarning,
                        stacklevel=4,
                    )
                    self.has_warnings = True
                else:
                    yield candidate

        applicable_cans_python_compatible = LazySequence(filter_candidates_with_requires_python(applicable_cans))
        # Evaluate data-requires-python attr and discard incompatible candidates
        # to reduce the number of candidates to resolve.
        if applicable_cans_python_compatible:
            applicable_cans = applicable_cans_python_compatible

        if not applicable_cans:
            termui.logger.debug("\tCould not find any matching candidates.")

        if not applicable_cans and allow_prereleases is None:
            # No non-pre-releases is found, force pre-releases now
            applicable_cans = LazySequence(
                c
                for c in cans
                if requirement.specifier.contains(c.version, True)  # type: ignore[arg-type, union-attr]
            )
            applicable_cans_python_compatible = LazySequence(filter_candidates_with_requires_python(applicable_cans))
            if applicable_cans_python_compatible:
                applicable_cans = applicable_cans_python_compatible

            if not applicable_cans:
                termui.logger.debug(
                    "\tCould not find any matching candidates even when considering pre-releases.",
                )

        def log_candidates(title: str, candidates: Iterable[Candidate], max_lines: int = 10) -> None:
            termui.logger.debug("\t" + title)
            logged_lines = set()
            for can in candidates:
                new_line = f"\t  {can!r}"
                if new_line not in logged_lines:
                    logged_lines.add(new_line)
                    if len(logged_lines) > max_lines:
                        termui.logger.debug("\t  ... [more]")
                        break
                    else:
                        termui.logger.debug(new_line)

        if self.environment.project.core.ui.verbosity >= termui.Verbosity.DEBUG:
            if applicable_cans:
                log_candidates("Found matching candidates:", applicable_cans)
            elif cans:
                log_candidates("Found but non-matching candidates:", cans)

        return applicable_cans
Find candidates of the given NamedRequirement. Let it to be implemented in
        subclasses.

        :param requirement: the requirement to find
        :param allow_prereleases: whether to include pre-releases
        :param ignore_requires_python: whether to ignore the requires-python marker
        :param minimal_version: whether to prefer the minimal versions of the package
        
src/pdm/models/repositories/base.py