Repository: openai/openai-python
File: src/openai/_client.py (Python)

Code before:
        from .resources.evals import Evals

        return Evals(self)

    @cached_property
    def containers(self) -> Containers:
        from .resources.containers import Containers

        return Containers(self)

    @cached_property
    def with_raw_response(self) -> OpenAIWithRawResponse:
        return OpenAIWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> OpenAIWithStreamedResponse:
        return OpenAIWithStreamedResponse(self)

    @property
    @override
    def qs(self) -> Querystring:
        return Querystring(array_format="brackets")

    def refresh_auth_headers(self) -> None:
        if self.bearer_token_provider:
            secret = self.bearer_token_provider()
        else:
            secret = self.api_key
        if not secret:
            # if the api key is an empty string, encoding the header will fail
            # so we set it to an empty dict
            # this is to avoid sending an invalid Authorization header
            self._auth_headers = {}
        else:
            self._auth_headers = {"Authorization": f"Bearer {secret}"}

    @override
    def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
        self.refresh_auth_headers()
        return super()._prepare_options(options)

    @property
    @override
    def auth_headers(self) -> dict[str, str]:
        return self._auth_headers

    @property
    @override
    def default_headers(self) -> dict[str, str | Omit]:
        return {
            **super().default_headers,

Review comment (bug):
do you have any fud around just setting `self.api_key` directly and keeping `def auth_headers()` mostly as-is?

this code feels prone to weird behaviour if a user ever mutates `client.api_key` as we *may* use the version that's cached from `self._auth_headers` instead. based on the current implementation that should basically be impossible to actually cause a bug as far as I can tell but I'd prefer to completely avoid that possibility.

Code after:

        return Conversations(self)

    @cached_property
    def evals(self) -> Evals:
        from .resources.evals import Evals

        return Evals(self)

    @cached_property
    def containers(self) -> Containers:
        from .resources.containers import Containers

        return Containers(self)

    @cached_property
    def with_raw_response(self) -> OpenAIWithRawResponse:
        return OpenAIWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> OpenAIWithStreamedResponse:
        return OpenAIWithStreamedResponse(self)

    @property
    @override
    def qs(self) -> Querystring:
        return Querystring(array_format="brackets")

    def _refresh_api_key(self) -> None:
        if self._api_key_provider:
            self.api_key = self._api_key_provider()

    @override
    def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
        self._refresh_api_key()
        return super()._prepare_options(options)

    @property
    @override
    def auth_headers(self) -> dict[str, str]:
        api_key = self.api_key
        if not api_key:
            # if the api key is an empty string, encoding the header will fail
            return {}
        return {"Authorization": f"Bearer {api_key}"}

    @property
    @override
    def default_headers(self) -> dict[str, str | Omit]:
        return {
            **super().default_headers,