Skip to content

Move normalize header functions from _utils.py to _models.py#3382

Merged
lovelydinosaur merged 2 commits intoencode:masterfrom
AstralScribe:master
Oct 30, 2024
Merged

Move normalize header functions from _utils.py to _models.py#3382
lovelydinosaur merged 2 commits intoencode:masterfrom
AstralScribe:master

Conversation

@AstralScribe
Copy link
Copy Markdown
Contributor

Summary

Issue: #3381

This PR refactors the normalize_header_key as an inline method and moves normalize_header_value function to _models.py from _utils.py.

Checklist

  • I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.

@AstralScribe AstralScribe marked this pull request as draft October 30, 2024 11:29
@AstralScribe AstralScribe marked this pull request as ready for review October 30, 2024 11:29
@lovelydinosaur
Copy link
Copy Markdown
Contributor

Thanks. ☺️

I'd suggest we should stay consistent and use _normalize_header_key() and _normalize_header_value() here.
There's perhaps some more cleanup we could do in this particular case, but that's probably the best starting point.

@AstralScribe
Copy link
Copy Markdown
Contributor Author

I have converted the inline method into a similar function.

@AstralScribe
Copy link
Copy Markdown
Contributor Author

I have done some more refactoring, but I am not sure if this simplifies or complicates it. I had to add some things due to mypy type checking.

def _convert_mapping_to_sequence(
    mappings: typing.Union[typing.Mapping[str, str], typing.Mapping[bytes, bytes]],
) -> typing.Sequence[typing.Tuple[str | bytes, str | bytes]]:
    return [(k, v) for k, v in mappings.items()]


def _normalize_headers(
    headers: HeaderTypes | None, encoding: str | None
) -> list[tuple[bytes, bytes, bytes]]:
    """
    Coerce str/bytes into a strictly byte-wise HTTP headers.
    """
    if headers is None:
        return []

    if isinstance(headers, Headers):
        return list(headers._list)

    normalized_list: list[tuple[bytes, bytes, bytes]] = []

    if isinstance(headers, typing.Mapping):
        n_headers = _convert_mapping_to_sequence(headers)
    elif isinstance(headers, typing.Sequence):
        n_headers = headers

    for key, value in n_headers:
        if not isinstance(value, (str, bytes)):
            raise TypeError(f"Header value must be str or bytes, not {type(value)}")
        b_key = key if isinstance(key, bytes) else key.encode(encoding or "ascii")
        b_value = (
            value if isinstance(value, bytes) else value.encode(encoding or "ascii")
        )
        normalized_list.append((b_key, b_key.lower(), b_value))

    return normalized_list

It replaces the whole init with:

self._list = _normalize_headers(headers, encoding)

Copy link
Copy Markdown
Contributor

@lovelydinosaur lovelydinosaur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly like this, yep. 👍
Just helps keep things neat & localised.

@lovelydinosaur lovelydinosaur added the refactor Issues and PRs related to code refactoring label Oct 30, 2024
@lovelydinosaur lovelydinosaur merged commit 83a8518 into encode:master Oct 30, 2024
@lovelydinosaur
Copy link
Copy Markdown
Contributor

Thanks @AstralScribe. 😊

I have done some more refactoring, but I am not sure if this simplifies or complicates it. I had to add some things due to mypy type checking.

Let's take a pass on that particular follow-up. What you've got here is great as it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Issues and PRs related to code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants