Repository: encode/httpx
File: httpx/_multipart.py (Python)

Code before:
        # It would be good to think of better APIs for this that we could include in httpx 2.0
        # since variable length tuples (especially of 4 elements) are quite unwieldly
        if isinstance(value, tuple):
            try:
                filename, fileobj, content_type, headers = value  # type: ignore
            except ValueError:
                # 4th parameter (headers) not included
                try:
                    filename, fileobj, content_type = value  # type: ignore
                except ValueError:
                    # neither the 3rd parameter (content_type) nor the 4th (headers) was included
                    filename, fileobj = value  # type: ignore
            else:
                # corresponds to (filename, fileobj, content_type, headers)
                headers = {k.title(): v for k, v in headers.items()}
        else:
            filename = Path(str(getattr(value, "name", "upload"))).name
            fileobj = value

        if content_type is None:
            content_type = guess_content_type(filename)

        if content_type is not None and "Content-Type" not in headers:
            # note that unlike requests, we ignore the content_type
            # provided in the 3rd tuple element if it is also included in the headers
            # requests does the opposite
            headers["Content-Type"] = content_type

        if isinstance(fileobj, (str, io.StringIO)):
            raise TypeError(f"Expected bytes or bytes-like object got: {type(fileobj)}")

        self.filename = filename
        self.file = fileobj
        self.headers = headers
        self._consumed = False

    def get_length(self) -> int:
        headers = self.render_headers()

        if isinstance(self.file, (str, bytes)):
            return len(headers) + len(to_bytes(self.file))

        # Let's do our best not to read `file` into memory.
        file_length = peek_filelike_length(self.file)
        if file_length is None:
            # As a last resort, read file and cache contents for later.
            assert not hasattr(self, "_data")
            self._data = to_bytes(self.file.read())
            file_length = len(self._data)

        return len(headers) + file_length

Review comment (suggestion):
Okay maybe we should instead do it the other way. If the 4-tuple is used, just ignore the `content_type` variable. That'd be okay enough, matches `requests` more closely, and we can forget about fiddly case-based header checking.

Code after:
        # It would be good to think of better APIs for this that we could include in httpx 2.0
        # since variable length tuples (especially of 4 elements) are quite unwieldly
        if isinstance(value, tuple):
            if len(value) == 2:
                # neither the 3rd parameter (content_type) nor the 4th (headers) was included
                filename, fileobj = value  # type: ignore
            elif len(value) == 3:
                filename, fileobj, content_type = value  # type: ignore
            else:
                # all 4 parameters included
                filename, fileobj, content_type, headers = value  # type: ignore
        else:
            filename = Path(str(getattr(value, "name", "upload"))).name
            fileobj = value

        if content_type is None:
            content_type = guess_content_type(filename)

        has_content_type_header = any("content-type" in key.lower() for key in headers)
        if content_type is not None and not has_content_type_header:
            # note that unlike requests, we ignore the content_type
            # provided in the 3rd tuple element if it is also included in the headers
            # requests does the opposite (it overwrites the header with the 3rd tuple element)
            headers["Content-Type"] = content_type

        if isinstance(fileobj, (str, io.StringIO)):
            raise TypeError(f"Expected bytes or bytes-like object got: {type(fileobj)}")

        self.filename = filename
        self.file = fileobj
        self.headers = headers
        self._consumed = False

    def get_length(self) -> int:
        headers = self.render_headers()

        if isinstance(self.file, (str, bytes)):
            return len(headers) + len(to_bytes(self.file))

        # Let's do our best not to read `file` into memory.
        file_length = peek_filelike_length(self.file)
        if file_length is None:
            # As a last resort, read file and cache contents for later.
            assert not hasattr(self, "_data")
            self._data = to_bytes(self.file.read())
            file_length = len(self._data)

        return len(headers) + file_length

    def render_headers(self) -> bytes:
        if not hasattr(self, "_headers"):