@_helpers.positional(<NUM_LIT:2>)<EOL><INDENT>def step2_exchange(self, code=None, http=None, device_flow_info=None):<DEDENT>
if code is None and device_flow_info is None:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if code is not None and device_flow_info is not None:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if code is None:<EOL><INDENT>code = device_flow_info.device_code<EOL><DEDENT>elif not isinstance(code, (six.string_types, six.binary_type)):<EOL><INDENT>if '<STR_LIT:code>' not in code:<EOL><INDENT>raise FlowExchangeError(code.get(<EOL>'<STR_LIT:error>', '<STR_LIT>'))<EOL><DEDENT>code = code['<STR_LIT:code>']<EOL><DEDENT>post_data = {<EOL>'<STR_LIT>': self.client_id,<EOL>'<STR_LIT:code>': code,<EOL>'<STR_LIT>': self.scope,<EOL>}<EOL>if self.client_secret is not None:<EOL><INDENT>post_data['<STR_LIT>'] = self.client_secret<EOL><DEDENT>if self._pkce:<EOL><INDENT>post_data['<STR_LIT>'] = self.code_verifier<EOL><DEDENT>if device_flow_info is not None:<EOL><INDENT>post_data['<STR_LIT>'] = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>post_data['<STR_LIT>'] = '<STR_LIT>'<EOL>post_data['<STR_LIT>'] = self.redirect_uri<EOL><DEDENT>body = urllib.parse.urlencode(post_data)<EOL>headers = {<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>}<EOL>if self.authorization_header is not None:<EOL><INDENT>headers['<STR_LIT>'] = self.authorization_header<EOL><DEDENT>if self.user_agent is not None:<EOL><INDENT>headers['<STR_LIT>'] = self.user_agent<EOL><DEDENT>if http is None:<EOL><INDENT>http = transport.get_http_object()<EOL><DEDENT>resp, content = transport.request(<EOL>http, self.token_uri, method='<STR_LIT:POST>', body=body, headers=headers)<EOL>d = _parse_exchange_token_response(content)<EOL>if resp.status == http_client.OK and '<STR_LIT>' in d:<EOL><INDENT>access_token = d['<STR_LIT>']<EOL>refresh_token = d.get('<STR_LIT>', None)<EOL>if not refresh_token:<EOL><INDENT>logger.info(<EOL>'<STR_LIT>'<EOL>"<STR_LIT>")<EOL><DEDENT>token_expiry = None<EOL>if '<STR_LIT>' in d:<EOL><INDENT>delta = datetime.timedelta(seconds=int(d['<STR_LIT>']))<EOL>token_expiry = delta + _UTCNOW()<EOL><DEDENT>extracted_id_token = None<EOL>id_token_jwt = None<EOL>if '<STR_LIT>' in d:<EOL><INDENT>extracted_id_token = _extract_id_token(d['<STR_LIT>'])<EOL>id_token_jwt = d['<STR_LIT>']<EOL><DEDENT>logger.info('<STR_LIT>')<EOL>return OAuth2Credentials(<EOL>access_token, self.client_id, self.client_secret,<EOL>refresh_token, token_expiry, self.token_uri, self.user_agent,<EOL>revoke_uri=self.revoke_uri, id_token=extracted_id_token,<EOL>id_token_jwt=id_token_jwt, token_response=d, scopes=self.scope,<EOL>token_info_uri=self.token_info_uri)<EOL><DEDENT>else:<EOL><INDENT>logger.info('<STR_LIT>', content)<EOL>if '<STR_LIT:error>' in d:<EOL><INDENT>error_msg = (str(d['<STR_LIT:error>']) +<EOL>str(d.get('<STR_LIT>', '<STR_LIT>')))<EOL><DEDENT>else:<EOL><INDENT>error_msg = '<STR_LIT>'.format(str(resp.status))<EOL><DEDENT>raise FlowExchangeError(error_msg)<EOL><DEDENT>
Exchanges a code for OAuth2Credentials.

        Args:
            code: string, a dict-like object, or None. For a non-device
                  flow, this is either the response code as a string, or a
                  dictionary of query parameters to the redirect_uri. For a
                  device flow, this should be None.
            http: httplib2.Http, optional http instance to use when fetching
                  credentials.
            device_flow_info: DeviceFlowInfo, return value from step1 in the
                              case of a device flow.

        Returns:
            An OAuth2Credentials object that can be used to authorize requests.

        Raises:
            FlowExchangeError: if a problem occurred exchanging the code for a
                               refresh_token.
            ValueError: if code and device_flow_info are both provided or both
                        missing.