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

Code before:

    retry_count: Annotated[int, Field(alias='retryCount')] = 0
    """Number of times the request has been retried."""

    no_retry: Annotated[bool, Field(alias='noRetry')] = False
    """If set to `True`, the request will not be retried in case of failure."""

    loaded_url: Annotated[str | None, BeforeValidator(validate_http_url), Field(alias='loadedUrl')] = None
    """URL of the web page that was loaded. This can differ from the original URL in case of redirects."""

    handled_at: Annotated[datetime | None, Field(alias='handledAt')] = None
    """Timestamp when the request was handled."""

    @field_validator('payload', mode='before')
    @classmethod
    def _payload_validation(cls, v: str | bytes | None) -> bytes | None:
        if isinstance(v, str):
            v = v.encode()
        return v

    @field_serializer('payload')
    @classmethod
    def _payload_serializer(cls, v: bytes | None) -> str | None:
        if isinstance(v, bytes):
            return v.decode()
        return None

    @classmethod
    def from_url(
        cls,
        url: str,
        *,
        method: HttpMethod = 'GET',
        headers: HttpHeaders | dict[str, str] | None = None,
        payload: HttpPayload | None = None,
        label: str | None = None,
        unique_key: str | None = None,
        id: str | None = None,
        keep_url_fragment: bool = False,
        use_extended_unique_key: bool = False,
        **kwargs: Any,
    ) -> Self:
        """Create a new `BaseRequestData` instance from a URL. See `Request.from_url` for more details."""
        if isinstance(headers, dict) or headers is None:
            headers = HttpHeaders(headers or {})

        unique_key = unique_key or compute_unique_key(
            url,
            method=method,
            headers=headers,
            payload=payload,

Review comment (suggestion):
Could we do this directly on the field by using Pydantic's `Annotated`? Like we do for the other fields.

Something like this:

```python
    payload: Annotated[
        HttpPayload | None,
        BeforeValidator(lambda v: v.encode() if isinstance(v, str) else v),
        PlainSerializer(lambda v: v.decode() if isinstance(v, bytes) else None),
    ] = None
    """HTTP request payload."""
```    

Code after:

    loaded_url: Annotated[str | None, BeforeValidator(validate_http_url), Field(alias='loadedUrl')] = None
    """URL of the web page that was loaded. This can differ from the original URL in case of redirects."""

    handled_at: Annotated[datetime | None, Field(alias='handledAt')] = None
    """Timestamp when the request was handled."""

    @classmethod
    def from_url(
        cls,
        url: str,
        *,
        method: HttpMethod = 'GET',
        headers: HttpHeaders | dict[str, str] | None = None,
        payload: HttpPayload | None = None,
        label: str | None = None,
        unique_key: str | None = None,
        id: str | None = None,
        keep_url_fragment: bool = False,
        use_extended_unique_key: bool = False,
        **kwargs: Any,
    ) -> Self:
        """Create a new `BaseRequestData` instance from a URL. See `Request.from_url` for more details."""
        if isinstance(headers, dict) or headers is None:
            headers = HttpHeaders(headers or {})

        unique_key = unique_key or compute_unique_key(
            url,
            method=method,
            headers=headers,
            payload=payload,
            keep_url_fragment=keep_url_fragment,
            use_extended_unique_key=use_extended_unique_key,
        )

        id = id or unique_key_to_request_id(unique_key)

        request = cls(
            url=url,
            unique_key=unique_key,
            id=id,
            method=method,
            headers=headers,
            payload=payload,
            **kwargs,
        )

        if label is not None:
            request.user_data['label'] = label

        return request