Repository: apify/crawlee-python
File: src/crawlee/proxy_configuration.py (Python)

Code before:

        self._proxy_urls = [self._create_url(url) for url in proxy_urls] if proxy_urls else []
        self._proxy_tier_tracker = (
            _ProxyTierTracker([[self._create_url(url) for url in tier] for tier in tiered_proxy_urls])
            if tiered_proxy_urls
            else None
        )
        self._new_url_function = new_url_function

    def _create_url(self, url: str | None) -> URL | None:
        """Create URL from input string. None means that intentionally no proxy should be used."""
        if url is None:
            return None

        self._url_validator.validate_python(url)
        return URL(url)

    async def new_proxy_info(
        self, session_id: str | None, request: Request | None, proxy_tier: int | None
    ) -> ProxyInfo | None:
        """Return a new ProxyInfo object.

        If called repeatedly with the same request, it is assumed that the request is being retried.
        If a previously used session ID is received, it will return the same proxy url.
        If neither session_id nor request is provided, a new proxy url will be returned on each call.
        """
        if self._proxy_tier_tracker is not None and session_id is None:
            session_id = crypto_random_object_id(6)

        url, proxy_tier = await self._pick_url(session_id, request, proxy_tier)

        if url is None:
            return None

        if url.port is None:
            raise ValueError(f'Port is None for URL: {url}')

        if url.host is None:
            raise ValueError(f'Host is None for URL: {url}')

        info = ProxyInfo(
            url=str(url),
            scheme=url.scheme,
            hostname=url.host,
            port=url.port,
            username=url.user or '',
            password=url.password or '',
        )

        if session_id is not None:
            info.session_id = session_id

Review comment (security):
Could you please add the `Args` section and describe all of them? It is probably one of the last public components where it is missing.

Same for the `new_url` method.

(I am sorry, I know you are not an author of that and these are not your changes.)

Code after:

        self._proxy_urls = [self._create_url(url) for url in proxy_urls] if proxy_urls else []
        self._proxy_tier_tracker = (
            _ProxyTierTracker([[self._create_url(url) for url in tier] for tier in tiered_proxy_urls])
            if tiered_proxy_urls
            else None
        )
        self._new_url_function = new_url_function

    def _create_url(self, url: str | None) -> URL | None:
        """Create URL from input string. None means that intentionally no proxy should be used."""
        if url is None:
            return None

        self._url_validator.validate_python(url)
        return URL(url)

    async def new_proxy_info(
        self, session_id: str | None, request: Request | None, proxy_tier: int | None
    ) -> ProxyInfo | None:
        """Returns a new ProxyInfo object based on the configured proxy rotation strategy.

        Args:
            session_id: Session identifier. If provided, same proxy URL will be returned for
                subsequent calls with this ID. Will be auto-generated for tiered proxies if
                not provided.
            request: Request object used for proxy rotation and tier selection. Required for
                tiered proxies to track retries and adjust tier accordingly.
            proxy_tier: Specific proxy tier to use. If not provided, will be automatically
                selected based on configuration.
        """
        if self._proxy_tier_tracker is not None and session_id is None:
            session_id = crypto_random_object_id(6)

        url, proxy_tier = await self._pick_url(session_id, request, proxy_tier)

        if url is None:
            return None

        if url.port is None:
            raise ValueError(f'Port is None for URL: {url}')

        if url.host is None:
            raise ValueError(f'Host is None for URL: {url}')

        info = ProxyInfo(
            url=str(url),
            scheme=url.scheme,
            hostname=url.host,
            port=url.port,
            username=url.user or '',