将 google-auth 与 gspread 一起使用时,“'Credentials' 对象没有属性 'access_token'”
"'Credentials' object has no attribute 'access_token'" when using google-auth with gspread
我想使用 gspread
module to edit Google sheets from Python. The setup instructions 包含以下示例:
import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('gspread-april-2cd … ba4.json', scope)
gc = gspread.authorize(credentials)
然而,根据https://pypi.org/project/oauth2client/ the oauth2client
library is deprecated. So I've tried to adapt this as follows, using google-auth
:
import gspread
from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file(
'my_client_secrets.json')
scoped_credentials = credentials.with_scopes(
['https://www.googleapis.com/auth/spreadsheets'])
gc = gspread.authorize(scoped_credentials)
不幸的是,我 运行 遇到以下错误:
(lucy-web-CVxkrCFK) bash-3.2$ python nps.py
Traceback (most recent call last):
File "nps.py", line 54, in <module>
gc = gspread.authorize(scoped_credentials)
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/gspread/__init__.py", line 38, in authorize
client.login()
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/gspread/client.py", line 46, in login
if not self.auth.access_token or \
AttributeError: 'Credentials' object has no attribute 'access_token'
如果我进入调试器,我确实看到 credentials
有一个 token
属性,但没有 access_token
属性:
> /Users/kurtpeek/Documents/Dev/lucy2/lucy-web/scripts/nps.py(54)<module>()
53 import ipdb; ipdb.set_trace()
---> 54 gc = gspread.authorize(scoped_credentials)
55
ipdb> type(credentials)
<class 'google.oauth2.service_account.Credentials'>
ipdb> type(scoped_credentials)
<class 'google.oauth2.service_account.Credentials'>
ipdb> dir(credentials)
['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_impl', '_additional_claims', '_from_signer_and_info', '_make_authorization_grant_assertion', '_project_id', '_scopes', '_service_account_email', '_signer', '_subject', '_token_uri', 'apply', 'before_request', 'expired', 'expiry', 'from_service_account_file', 'from_service_account_info', 'has_scopes', 'project_id', 'refresh', 'requires_scopes', 'scopes', 'service_account_email', 'sign_bytes', 'signer', 'signer_email', 'token', 'valid', 'with_claims', 'with_scopes', 'with_subject']
google-auth
生成的Credentials
和oauth2client
生成的对象不是同一个对象吗?
根据 gspread
文档,gspread.authorize method only supports credential objects that are created by the oauth2client library. To work with the new google-auth gspread 应该添加对它的支持。
如果您不想使用已弃用的 oauthclient2,可能的解决方法是使用 authlib leveraging the session parameter of the gspread.Client class. There is a nice tutorial on how to do this here.
2020 年 4 月 27 日更新
从 version 3.4.0 gspread is now supporting google-auth. You can find all the details in the dedicated documentation 开始。这是作者的官方声明:
Older versions of gspread have used oauth2client. Google has deprecated it in favor of google-auth. If you’re still using oauth2client credentials, the library will convert these to google-auth for you, but you can change your code to use the new credentials to make sure nothing breaks in the future.
作为创可贴修复,您可以创建一个新的 class 来继承凭据并添加一个新的 access_token
属性 来反映凭据中的令牌。然后将其传递给 gspread.authorize
,它应该可以工作。
# create the new class to fix credentials
class fixed_creds(service_account.Credentials):
def __init__(self, creds):
self.access_token = creds.token
# create new credential object with the access_token
gcreds = fixed_creds(credentials)
# pass new credentials into gspread
sheets = gspread.authorize(gcreds)
# create a new sheet to test it
new_sheet = sheets.create('TestSheet')
# give yourself permission to see the new sheet
sheets.insert_permission(
new_sheet.id,
'youremail@yourdomain.com',
perm_type='user',
role='writer'
)
Tom 的创可贴修复对我不起作用,因为 token
最初是 None
在 Google OAuth2 库中。这是我的创可贴修复方法:
import gspread
import google.auth.transport.requests
from google.oauth2 import service_account
from oauth2client.service_account import ServiceAccountCredentials
class OAuth2ServiceAccountFromGoogleOAuth2(ServiceAccountCredentials): # Hack based upon
def __init__(self, google_oauth2_credentials):
self.google_oauth2_credentials = google_oauth2_credentials
self.access_token = google_oauth2_credentials.token
def refresh(self, http):
if self.access_token is None:
request = google.auth.transport.requests.Request()
self.google_oauth2_credentials.refresh(request)
self.access_token = self.google_oauth2_credentials.token
#end if
print(f'access token in {self.access_token}')
#end def
#end class
with open("credentials.json") as gs_key_file:
google_credentials = service_account.Credentials.from_service_account_info(json.loads(gs_key_file.read()), scopes=['https://www.googleapis.com/auth/spreadsheets'])
gclient = gspread.authorize(OAuth2ServiceAccountFromGoogleOAuth2(google_credentials))
一年半后,在完全相同的情况下,我发现这对我有用:
import gspread
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
credentials = service_account.Credentials.from_service_account_file(
'your_key_file.json')
scoped_credentials = credentials.with_scopes(
['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
)
gc = gspread.Client(auth=scoped_credentials)
gc.session = AuthorizedSession(scoped_credentials)
sheet = gc.open_by_key('key_in_sharelink')
print(sheet.title)
解决方案改编自 this post in gspread github and the google-auth
user guide。
我想使用 gspread
module to edit Google sheets from Python. The setup instructions 包含以下示例:
import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('gspread-april-2cd … ba4.json', scope)
gc = gspread.authorize(credentials)
然而,根据https://pypi.org/project/oauth2client/ the oauth2client
library is deprecated. So I've tried to adapt this as follows, using google-auth
:
import gspread
from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file(
'my_client_secrets.json')
scoped_credentials = credentials.with_scopes(
['https://www.googleapis.com/auth/spreadsheets'])
gc = gspread.authorize(scoped_credentials)
不幸的是,我 运行 遇到以下错误:
(lucy-web-CVxkrCFK) bash-3.2$ python nps.py
Traceback (most recent call last):
File "nps.py", line 54, in <module>
gc = gspread.authorize(scoped_credentials)
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/gspread/__init__.py", line 38, in authorize
client.login()
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/gspread/client.py", line 46, in login
if not self.auth.access_token or \
AttributeError: 'Credentials' object has no attribute 'access_token'
如果我进入调试器,我确实看到 credentials
有一个 token
属性,但没有 access_token
属性:
> /Users/kurtpeek/Documents/Dev/lucy2/lucy-web/scripts/nps.py(54)<module>()
53 import ipdb; ipdb.set_trace()
---> 54 gc = gspread.authorize(scoped_credentials)
55
ipdb> type(credentials)
<class 'google.oauth2.service_account.Credentials'>
ipdb> type(scoped_credentials)
<class 'google.oauth2.service_account.Credentials'>
ipdb> dir(credentials)
['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_impl', '_additional_claims', '_from_signer_and_info', '_make_authorization_grant_assertion', '_project_id', '_scopes', '_service_account_email', '_signer', '_subject', '_token_uri', 'apply', 'before_request', 'expired', 'expiry', 'from_service_account_file', 'from_service_account_info', 'has_scopes', 'project_id', 'refresh', 'requires_scopes', 'scopes', 'service_account_email', 'sign_bytes', 'signer', 'signer_email', 'token', 'valid', 'with_claims', 'with_scopes', 'with_subject']
google-auth
生成的Credentials
和oauth2client
生成的对象不是同一个对象吗?
根据 gspread
文档,gspread.authorize method only supports credential objects that are created by the oauth2client library. To work with the new google-auth gspread 应该添加对它的支持。
如果您不想使用已弃用的 oauthclient2,可能的解决方法是使用 authlib leveraging the session parameter of the gspread.Client class. There is a nice tutorial on how to do this here.
2020 年 4 月 27 日更新
从 version 3.4.0 gspread is now supporting google-auth. You can find all the details in the dedicated documentation 开始。这是作者的官方声明:
Older versions of gspread have used oauth2client. Google has deprecated it in favor of google-auth. If you’re still using oauth2client credentials, the library will convert these to google-auth for you, but you can change your code to use the new credentials to make sure nothing breaks in the future.
作为创可贴修复,您可以创建一个新的 class 来继承凭据并添加一个新的 access_token
属性 来反映凭据中的令牌。然后将其传递给 gspread.authorize
,它应该可以工作。
# create the new class to fix credentials
class fixed_creds(service_account.Credentials):
def __init__(self, creds):
self.access_token = creds.token
# create new credential object with the access_token
gcreds = fixed_creds(credentials)
# pass new credentials into gspread
sheets = gspread.authorize(gcreds)
# create a new sheet to test it
new_sheet = sheets.create('TestSheet')
# give yourself permission to see the new sheet
sheets.insert_permission(
new_sheet.id,
'youremail@yourdomain.com',
perm_type='user',
role='writer'
)
Tom 的创可贴修复对我不起作用,因为 token
最初是 None
在 Google OAuth2 库中。这是我的创可贴修复方法:
import gspread
import google.auth.transport.requests
from google.oauth2 import service_account
from oauth2client.service_account import ServiceAccountCredentials
class OAuth2ServiceAccountFromGoogleOAuth2(ServiceAccountCredentials): # Hack based upon
def __init__(self, google_oauth2_credentials):
self.google_oauth2_credentials = google_oauth2_credentials
self.access_token = google_oauth2_credentials.token
def refresh(self, http):
if self.access_token is None:
request = google.auth.transport.requests.Request()
self.google_oauth2_credentials.refresh(request)
self.access_token = self.google_oauth2_credentials.token
#end if
print(f'access token in {self.access_token}')
#end def
#end class
with open("credentials.json") as gs_key_file:
google_credentials = service_account.Credentials.from_service_account_info(json.loads(gs_key_file.read()), scopes=['https://www.googleapis.com/auth/spreadsheets'])
gclient = gspread.authorize(OAuth2ServiceAccountFromGoogleOAuth2(google_credentials))
一年半后,在完全相同的情况下,我发现这对我有用:
import gspread
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
credentials = service_account.Credentials.from_service_account_file(
'your_key_file.json')
scoped_credentials = credentials.with_scopes(
['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
)
gc = gspread.Client(auth=scoped_credentials)
gc.session = AuthorizedSession(scoped_credentials)
sheet = gc.open_by_key('key_in_sharelink')
print(sheet.title)
解决方案改编自 this post in gspread github and the google-auth
user guide。