diff --git a/aiogoogle/auth/creds.py b/aiogoogle/auth/creds.py index 92b95c2..3430617 100644 --- a/aiogoogle/auth/creds.py +++ b/aiogoogle/auth/creds.py @@ -31,111 +31,111 @@ class IdToken(_dict): iss (str): * PROVIDED: always - + * The Issuer Identifier for the Issuer of the response. Always https://accounts.google.com or accounts.google.com for Google ID tokens. - + at_hash (str): - + * Access token hash. - + * Provides validation that the access token is tied to the identity token. - + * If the ID token is issued with an access token in the server flow, this is always included. - + * This can be used as an alternate mechanism to protect against cross-site request forgery attacks, but if you follow Step 1 and Step 3 it is not necessary to verify the access token. - + email_verified (bool) - + * True if the user's e-mail address has been verified; otherwise false. - + sub (str): * PROVIDED: always - + * An identifier for the user, unique among all Google accounts and never reused. - + * A Google account can have multiple emails at different points in time, but the sub value is never changed. - + * Use sub within your application as the unique-identifier key for the user. - + azp (str): - + * The client_id of the authorized presenter. - + * This claim is only needed when the party requesting the ID token is not the same as the audience of the ID token. - + * This may be the case at Google for hybrid apps where a web application and Android app have a different client_id but share the same project. - + email (str): - + * The user's email address. - + * This may not be unique and is not suitable for use as a primary key. - + * Provided only if your scope included the string "email". - + profile (str): - + * The URL of the user's profile page. Might be provided when: - + * The request scope included the string "profile" - + * The ID token is returned from a token refresh - - * When profile claims are present, you can use them to update your app's user records. - + + * When profile claims are present, you can use them to update your app's user records. + * Note that this claim is never guaranteed to be present. - + picture (str): - + * The URL of the user's profile picture. Might be provided when: - + * The request scope included the string "profile" - + * The ID token is returned from a token refresh - + * When picture claims are present, you can use them to update your app's user records. - + * Note that this claim is never guaranteed to be present. - + name (str): - + * The user's full name, in a displayable form. Might be provided when: - + * The request scope included the string "profile" - + * The ID token is returned from a token refresh - + * When name claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present. - + aud (str): - + * PROVIDED: always - + * The audience that this ID token is intended for. - + * It must be one of the OAuth 2.0 client IDs of your application. - + iat (str): - + * PROVIDED: always - + * The time the ID token was issued, represented in Unix time (integer seconds). - + exp (str): - + * PROVIDED: always - + * The time the ID token expires, represented in Unix time (integer seconds). - - nonce (str): - + + nonce (str): + * The value of the nonce supplied by your app in the authentication request. - + * You should enforce protection against replay attacks by ensuring it is presented only once. - + hd (str): - + * The hosted G Suite domain of the user. Provided only if the user belongs to a hosted domain. """ @@ -153,15 +153,15 @@ class UserCreds(_dict): expires_in (int): seconds till expiry from creation expires_at (str): JSON datetime ISO 8601 expiry datetime scopes (list): list of scopes owned by access token - + id_token (aiogoogle.auth.creds.IdToken): Decoded OpenID JWT id_token_jwt (str): Encoded OpenID JWT - + token_type (str): Bearer token_uri (str): URI where this token was issued from token_info_uri (str): URI where one could get more info about this token revoke_uri (str): URI where this token should be revoked - + """ def __init__( diff --git a/aiogoogle/auth/managers.py b/aiogoogle/auth/managers.py index fc6291a..935fb1c 100644 --- a/aiogoogle/auth/managers.py +++ b/aiogoogle/auth/managers.py @@ -1,7 +1,7 @@ """ .. note:: - * Aiogoogle is an async-framework agnosting library. As a result, adding file IO OR credentials storage capabilities for user credentials would add unneeded complexity. + * Aiogoogle is an async-framework agnosting library. As a result, adding file IO OR credentials storage capabilities for user credentials would add unneeded complexity. * Credentials are an instance of ``dict`` and are guaranteed to only contain JSON types (str, number, array, JSONSCHEMA datetime and ISO8601 datetime, etc) to make them easily serializable. """ @@ -156,9 +156,9 @@ def __getitem__(self, key): Example: * response_types_supported - + * scopes_supported - + * claims_supported """ try: @@ -190,7 +190,7 @@ async def _refresh_openid_configs(self): Unless this test is failing: - aiogoogle.tests.integ_online.latest_test_latest_openid_configs(), You shouldn't really need to use this. + aiogoogle.tests.integ_online.latest_test_latest_openid_configs(), You shouldn't really need to use this. """ req = Request("GET", url=OPENID_CONFIGS_DISCOVERY_DOC_URL) self.openid_configs = await self._send_request(req) @@ -229,7 +229,7 @@ def is_ready(self, client_creds=None): Returns: - bool: + bool: """ client_creds = client_creds or self.client_creds if ( @@ -253,7 +253,7 @@ def authorization_url( response_type=AUTH_CODE_RESPONSE_TYPE, scopes=None, ) -> (str): - """ + """ First step of OAuth2 authoriztion code flow. Creates an OAuth2 authorization URI. Arguments: @@ -271,27 +271,27 @@ def authorization_url( * Optional * Overrides the list of scopes specified in client creds - + state (str): A CSRF token * Optional * Specifies any string value that your application uses to maintain state between your authorization request and the authorization server's response. - + * The server returns the exact value that you send as a name=value pair in the hash (#) fragment of the redirect_uri after the user consents to or denies your application's access request. * You can use this parameter for several purposes, such as: - + * Directing the user to the correct resource in your application - + * Sending nonces - + * Mitigating cross-site request forgery. * If no state is passed, this method will generate and add a secret token to ``user_creds['state']``. - + * Since your redirect_uri can be guessed, using a state value can increase your assurance that an incoming connection is the result of an authentication request. - + * If you generate a random string or encode the hash of a cookie or another value that captures the client's state, you can validate the response to additionally ensure that the request and response originated in the same browser, providing protection against attacks such as cross-site request forgery. access_type (str): Indicates whether your application can refresh access tokens when the user is not present at the browser. Options: @@ -303,33 +303,33 @@ def authorization_url( * ``"offline"`` Choose this for a refresheable/long-term access token include_granted_scopes (bool): - + * Optional * Enables applications to use incremental authorization to request access to additional scopes in context. - + * If you set this parameter's value to ``True`` and the authorization request is granted, then the new access token will also cover any scopes to which the user previously granted the application access. login_hint (str): - + * Optional - + * If your application knows which user is trying to authenticate, it can use this parameter to provide a hint to the Google Authentication Server. - + * The server uses the hint to simplify the login flow either by prefilling the email field in the sign-in form or by selecting the appropriate multi-login session. * Set the parameter value to an email address or sub identifier, which is equivalent to the user's Google ID. - + * This can help you avoid problems that occur if your app logs in the wrong user account. prompt (str): * Optional - + * A space-delimited, case-sensitive list of prompts to present the user. - + * If you don't specify this parameter, the user will be prompted only the first time your app requests access. - + * Possible values are: * ``None`` : Default: Do not display any authentication or consent screens. Must not be specified with other values. @@ -359,19 +359,19 @@ def authorization_url( * For a list of all of Google's available scopes: https://developers.google.com/identity/protocols/googlescopes * It is recommended that your application requests access to authorization scopes in context whenever possible. - + * By requesting access to user data in context, via incremental authorization, you help users to more easily understand why your application needs the access it is requesting. Warning: * When listening for a callback after redirecting a user to the URL returned from this method, take the following into consideration: - + * If your response endpoint renders an HTML page, any resources on that page will be able to see the authorization code in the URL. - + * Scripts can read the URL directly, and the URL in the Referer HTTP header may be sent to any or all resources on the page. * Carefully consider whether you want to send authorization credentials to all resources on that page (especially third-party scripts such as social plugins and analytics). - + * To avoid this issue, it's recommend that the server first handle the request, then redirect to another URL that doesn't include the response parameters. Example: @@ -431,9 +431,9 @@ async def build_user_creds( Arguments: grant (str): - - * Aka: "code". - + + * Aka: "code". + * The code received at your redirect URI from the auth callback client_creds (aiogoogle.auth.creds.ClientCreds): @@ -504,9 +504,9 @@ def _build_user_creds_from_res(self, json_res): def authorized_for_method(method, user_creds) -> bool: """ Checks if oauth2 user_creds dict has sufficient scopes for a method call. - - .. note:: - + + .. note:: + This method doesn't check whether creds are refreshed or valid. e.g. @@ -514,9 +514,9 @@ def authorized_for_method(method, user_creds) -> bool: **Correct:** .. code-block:: python3 - + is_authorized = authorized_for_method(youtube.video.list) - + **NOT correct:** .. code-block:: python3 @@ -595,7 +595,7 @@ def is_expired(creds) -> bool: Checks if user_creds expired Arguments: - + user_creds (aiogoogle.auth.creds.UserCreds): User Credentials Returns: @@ -608,7 +608,7 @@ def is_expired(creds) -> bool: async def refresh(self, user_creds, client_creds=None): """ Refreshes user_creds - + Arguments: user_creds (aiogoogle.auth.creds.UserCreds): User Credentials with ``refresh_token`` item @@ -617,7 +617,7 @@ async def refresh(self, user_creds, client_creds=None): Returns: - bool: If the token is refreshed or not + bool: If the token is refreshed or not aiogoogle.creds.UserCreds: Refreshed user credentials Raises: @@ -687,21 +687,21 @@ def __init__(self, *args, **kwargs): async def get_user_info(self, user_creds): """ https://developers.google.com/+/web/api/rest/openidconnect/getOpenIdConnect - + People: getOpenIdConnect - + Get user information after performing an OpenID connect flow. - + Use this method instead of people.get (Google+ API) when you need the OpenID Connect format. - - This method is not discoverable nor is it in the Google API client libraries. - + + This method is not discoverable nor is it in the Google API client libraries. + To learn more, see OpenID Connect for sign-in. https://developers.google.com/+/web/api/rest/openidconnect/index.html - + Example: - + :: - + >>> await get_user_info(user_creds) { "kind": "plus#personOpenIdConnect", @@ -728,13 +728,13 @@ async def get_user_info(self, user_creds): async def get_token_info_jwt(self, user_creds): """ get token info using id_token_jwt instead of access_token ``self.get_token_info`` - + Arguments: - + user_creds (aiogoogle.auth.creds.UserCreds): user_creds with id_token_jwt item - + Returns: - + dict: Information about the token """ req = self.oauth2_api.tokeninfo(id_token=user_creds.get("id_token_jwt")) @@ -763,7 +763,7 @@ def authorization_url( response_type=AUTH_CODE_RESPONSE_TYPE, scopes=None, ): - """ + """ First step of OAuth2 authoriztion code flow. Creates an OAuth2 authorization URI. Arguments: @@ -793,15 +793,15 @@ def authorization_url( * Optional * An ASCII string value for specifying how the authorization server displays the authentication and consent user interface pages. - + * The following values are specified, and accepted by the Google servers, but do not have any effect on its behavior: - + * ``page`` - + * ``popup`` - + * ``touch`` - + * ``wap`` state (str): A CSRF token @@ -809,21 +809,21 @@ def authorization_url( * Optional * Specifies any string value that your application uses to maintain state between your authorization request and the authorization server's response. - + * The server returns the exact value that you send as a name=value pair in the hash (#) fragment of the redirect_uri after the user consents to or denies your application's access request. * You can use this parameter for several purposes, such as: - + * Directing the user to the correct resource in your application - + * Sending nonces - + * Mitigating cross-site request forgery. * If no state is passed, this method will generate and add a secret token to ``user_creds['state']``. - + * Since your redirect_uri can be guessed, using a state value can increase your assurance that an incoming connection is the result of an authentication request. - + * If you generate a random string or encode the hash of a cookie or another value that captures the client's state, you can validate the response to additionally ensure that the request and response originated in the same browser, providing protection against attacks such as cross-site request forgery. access_type (str): Indicates whether your application can refresh access tokens when the user is not present at the browser. Options: @@ -835,19 +835,19 @@ def authorization_url( * ``"offline"`` Choose this for a refresheable/long-term access token include_granted_scopes (bool): - + * Optional * Enables applications to use incremental authorization to request access to additional scopes in context. - + * If you set this parameter's value to ``True`` and the authorization request is granted, then the new access token will also cover any scopes to which the user previously granted the application access. login_hint (str): - + * Optional - + * If your application knows which user is trying to authenticate, it can use this parameter to provide a hint to the Google Authentication Server. - + * The server uses the hint to simplify the login flow either by prefilling the email field in the sign-in form or by selecting the appropriate multi-login session. * Set the parameter value to an email address or sub identifier, which is equivalent to the user's Google ID. @@ -857,11 +857,11 @@ def authorization_url( prompt (str): * Optional - + * A space-delimited, case-sensitive list of prompts to present the user. - + * If you don't specify this parameter, the user will be prompted only the first time your app requests access. - + * Possible values are: * ``None`` : Default: Do not display any authentication or consent screens. Must not be specified with other values. @@ -875,11 +875,11 @@ def authorization_url( * Optional * openid.realm is a parameter from the OpenID 2.0 protocol. - + * It is used in OpenID 2.0 requests to signify the URL-space for which an authentication request is valid. - + * Use openid.realm if you are migrating an existing application from OpenID 2.0 to OpenID Connect. - + * For more details, see Migrating off of OpenID 2.0. https://developers.google.com/identity/protocols/OpenID2Migration hd (str): @@ -887,15 +887,15 @@ def authorization_url( * Optional * The hd (hosted domain) parameter streamlines the login process for G Suite hosted accounts. - + * By including the domain of the G Suite user (for example, mycollege.edu), you can indicate that the account selection UI should be optimized for accounts at that domain. - + * To optimize for G Suite accounts generally instead of just one domain, use an asterisk: hd=*. * Don't rely on this UI optimization to control who can access your app, as client-side requests can be modified. - + * Be sure to validate that the returned ID token has an hd claim value that matches what you expect (e.g. mycolledge.edu). - + * Unlike the request parameter, the ID token claim is contained within a security token from Google, so the value can be trusted. response_type (str): @@ -921,19 +921,19 @@ def authorization_url( * For a list of all of Google's available scopes: https://developers.google.com/identity/protocols/googlescopes * It is recommended that your application requests access to authorization scopes in context whenever possible. - + * By requesting access to user data in context, via incremental authorization, you help users to more easily understand why your application needs the access it is requesting. Warning: * When listening for a callback after redirecting a user to the URL returned from this method, take the following into consideration: - + * If your response endpoint renders an HTML page, any resources on that page will be able to see the authorization code in the URL. - + * Scripts can read the URL directly, and the URL in the Referer HTTP header may be sent to any or all resources on the page. * Carefully consider whether you want to send authorization credentials to all resources on that page (especially third-party scripts such as social plugins and analytics). - + * To avoid this issue, it's recommend that the server first handle the request, then redirect to another URL that doesn't include the response parameters. Example: @@ -1007,9 +1007,9 @@ async def build_user_creds( Arguments: grant (str): - - * Aka: "code". - + + * Aka: "code". + * The code received at your redirect URI from the auth callback client_creds (aiogoogle.auth.creds.ClientCreds): @@ -1238,7 +1238,7 @@ async def detect_default_creds_source(self): 4. Compute Engine default credentials Returns: - + None ''' if self.creds.get('private_key'): @@ -1298,7 +1298,7 @@ async def _get_oauth2_authorization_grant(self): additional_claims = creds.pop('additional_claims') except KeyError: additional_claims = None - + google_auth_lib_creds = service_account.Credentials.from_service_account_info( info=creds, scopes=scopes, diff --git a/aiogoogle/client.py b/aiogoogle/client.py index 9b551f7..132bd1a 100644 --- a/aiogoogle/client.py +++ b/aiogoogle/client.py @@ -27,7 +27,7 @@ class Aiogoogle: 2. Aiogoogle's OAuth2 manager 3. Aiogoogle's API key manager 4. Aiogoogle's OpenID Connect manager - 5. Aiogoogle's service account manager + 5. Aiogoogle's service account manager 6. One of Aiogoogle's implementations of a session object Arguments: @@ -35,17 +35,17 @@ class Aiogoogle: session_factory (aiogoogle.sessions.abc.AbstractSession): AbstractSession Implementation. Defaults to ``aiogoogle.sessions.aiohttp_session.AiohttpSession`` api_key (aiogoogle.auth.creds.ApiKey): Google API key - - user_creds (aiogoogle.auth.creds.UserCreds): OAuth2 cser credentials + + user_creds (aiogoogle.auth.creds.UserCreds): OAuth2 cser credentials client_creds (aiogoogle.auth.creds.ClientCreds): OAuth2 client credentials service_account_creds (aiogoogle.auth.creds.ServiceAccountCreds): Service account credentials - - Note: - + + Note: + In case you want to instantiate a custom session with initial parameters, you can pass an anonymous factory. e.g. :: - + >>> sess = lambda: Session(your_custome_arg, your_custom_kwarg=True) >>> aiogoogle = Aiogoogle(session_factory=sess) """ @@ -91,9 +91,9 @@ async def list_api(self, name, preferred=None, fields=None): https://developers.google.com/discovery/v1/reference/apis/list The discovery.apis.list method returns the list all APIs supported by the Google APIs Discovery Service. - + The data for each entry is a subset of the Discovery Document for that API, and the list provides a directory of supported APIs. - + If a specific API has multiple versions, each of the versions has its own entry in the list. Example: @@ -207,9 +207,9 @@ async def discover(self, api_name, api_version=None, validate=False, *, disco_do # -------- Send Requests ----------# async def as_user(self, *requests, timeout=None, full_res=False, user_creds=None, raise_for_status=True): - """ + """ Sends requests on behalf of ``self.user_creds`` (OAuth2) - + Arguments: *requests (aiogoogle.models.Request): @@ -265,9 +265,9 @@ async def as_user(self, *requests, timeout=None, full_res=False, user_creds=None async def as_service_account( self, *requests, timeout=None, full_res=False, service_account_creds=None, raise_for_status=True): - """ + """ Sends requests on behalf of ``self.user_creds`` (OAuth2) - + Arguments: *requests (aiogoogle.models.Request): @@ -314,9 +314,9 @@ async def as_service_account( ) async def as_api_key(self, *requests, timeout=None, full_res=False, api_key=None, raise_for_status=True): - """ + """ Sends requests on behalf of ``self.api_key`` (OAuth2) - + Arguments: *requests (aiogoogle.models.Request): @@ -362,9 +362,9 @@ async def as_api_key(self, *requests, timeout=None, full_res=False, api_key=None ) async def as_anon(self, *requests, timeout=None, full_res=False, raise_for_status=True): - """ + """ Sends unauthorized requests - + Arguments: *requests (aiogoogle.models.Request): diff --git a/aiogoogle/models.py b/aiogoogle/models.py index 3db0e41..e3809e2 100644 --- a/aiogoogle/models.py +++ b/aiogoogle/models.py @@ -10,14 +10,14 @@ class ResumableUpload: """ - Resumable Upload Object. Works in conjuction with media upload - + Resumable Upload Object. Works in conjuction with media upload + Arguments: file_path (str): Full path of the file to be uploaded - + upload_path (str): The URI path to be used for upload. Should be used in conjunction with the rootURL property at the API-level. - + multipart (bool): True if this endpoint supports upload multipart media. chunk_size (int): Size of a chunk of bytes that a session should read at a time when uploading in multipart. @@ -40,15 +40,15 @@ class MediaUpload: file_path_or_bytes (str, bytes): Full path or content of the file to be uploaded upload_path (str): The URI path to be used for upload. Should be used in conjunction with the rootURL property at the API-level. - + mime_range (list): list of MIME Media Ranges for acceptable media uploads to this method. - + max_size (int): Maximum size of a media upload in bytes - + multipart (bool): True if this endpoint supports upload multipart media. chunksize (int): Size of a chunk of bytes that a session should read at a time when uploading in multipart. - + resumable (aiogoogle.models.ResumableUplaod): A ResumableUpload object validate (bool): Whether or not a session should validate the upload size before sending @@ -143,31 +143,31 @@ class Request: Request class for the whole library. Auth Managers, GoogleAPI and Sessions should all use this. .. note:: - + For HTTP body, only pass one of the following params: - + - json: json as a dict - - data: www-url-form-encoded form as a dict/ bytes/ text/ + - data: www-url-form-encoded form as a dict/ bytes/ text/ Parameters: method (str): HTTP method as a string (upper case) e.g. 'GET' - + url (str): full url as a string. e.g. 'https://example.com/api/v1/resource?filter=filter#something batch_url (str): full url of for sending this request in a batch - + json (dict): json as a dict - - data (any): www-url-form-encoded form as a dict/ bytes/ text/ - + + data (any): www-url-form-encoded form as a dict/ bytes/ text/ + headers (dict): headers as a dict - + media_download (aiogoogle.models.MediaDownload): MediaDownload object - + media_upload (aiogoogle.models.MediaUpload): MediaUpload object - + timeout (int): Individual timeout for this request callback (callable): Synchronous callback that takes the content of the response as the only argument. Should also return content. @@ -278,7 +278,7 @@ class Response: pipe_from (file object): class object to stream file content from session_factory (aiogoogle.sessions.abc.AbstractSession): A callable implementation of aiogoogle's session interface - + auth_manager (aiogoogle.auth.managers.ServiceAccountManager): Service account authorization manager. user_creds (aiogoogle.auth.creds.UserCreds): user_creds to make an api call with. @@ -362,7 +362,7 @@ async def _next_page_generator( is_refreshed, user_creds = await prev_res.auth_manager.refresh(prev_res.user_creds) if is_refreshed and user_creds: prev_res.auth_manager.authorize(next_req, user_creds=user_creds) - + prev_res = await sess.send(next_req, full_res=True, auth_manager=prev_res.auth_manager, user_creds=user_creds) else: prev_res = None @@ -382,13 +382,13 @@ def __call__( session_factory (aiogoogle.sessions.abc.AbstractSession): A session factory req_token_name (str): - + * name of the next_page token in the request * Default: "pageToken" - - res_token_name (str): - + + res_token_name (str): + * name of the next_page token in json response * Default: "nextPageToken" @@ -429,13 +429,13 @@ def next_page( Arguments: req_token_name (str): - + * name of the next_page token in the request * Default: "pageToken" - - res_token_name (str): - + + res_token_name (str): + * name of the next_page token in json response * Default: "nextPageToken" diff --git a/aiogoogle/resource.py b/aiogoogle/resource.py index edc35b6..d79ac5f 100644 --- a/aiogoogle/resource.py +++ b/aiogoogle/resource.py @@ -43,7 +43,7 @@ def _temporarily_add_back_dashes_to_param_definitions(f): """ - When instantiating a Method, Method's constructor will remove all + When instantiating a Method, Method's constructor will remove all dashes from the names of its URI params and global params in order to make it possible to pass uri params through function calls e.g. this is viable get_videos(my_videos=True) @@ -215,7 +215,7 @@ def response(self) -> dict: @property def parameters(self) -> dict: - """ + """ Parameters property Returns: @@ -351,16 +351,16 @@ def __getitem__(self, key): :: - >>> self['description'] - + >>> self['description'] + "method description" >>> self['scopes'] - + ['returns', 'scopes', 'required', 'by', 'this', 'method', 'in', 'a', 'list'] >>> self['supportsMediaDownload'] - + False >>> self['supportsMediaUpload'] @@ -399,39 +399,39 @@ def __call__( path_params_safe_chars={}, **uri_params, ) -> Request: - """ + """ Builds a request from this method Note: * When passing ``datetime.datetime or datetime.date`` pass them in json format. - + * Aiogoogle won't do that as it would be a big hassle to iterate over every item in ``*uri_params``, ``json`` and ``data`` to check if there's any datetime objects. - * Fortunately Python makes it really easy to achieve that. - + * Fortunately Python makes it really easy to achieve that. + * Instead of passing say ``datetime.datetime.utcnow()``, pass: ``datetime.datetime.utcnow().jsonformat()`` Note: - * All ``None`` values are ommited before sending to Google apis, if you want to explicitly pass a JSON null then pass it as ``"null"`` not ``None`` + * All ``None`` values are ommited before sending to Google apis, if you want to explicitly pass a JSON null then pass it as ``"null"`` not ``None`` Arguments: validate (bool): Overrides :param: aiogoogle.Aiogoole.validate if not None - + json (dict): Json body - + data (any): Data body (Bytes, text, www-url-form-encoded and others) - + upload_file (str): full path of file to upload - + download_file (str): full path of file to download to - + timeout (str): total timeout for this request - + path_params_safe_chars (dict): Dictionary of safe characters for each path parameter. - + **uri_params (dict): path and query, required and optional parameters Returns: @@ -844,7 +844,7 @@ def __getattr__(self, method_or_resource): Note: - + This method will first check in nested resources then will check in methods. Raises: @@ -860,8 +860,8 @@ def __getattr__(self, method_or_resource): else: raise AttributeError( f"""Resource/Method {method_or_resource} doesn't exist. - Check: https://developers.google.com/ for more info. - \nAvailable resources are: + Check: https://developers.google.com/ for more info. + \nAvailable resources are: {self.resources_available}\n Available methods are {self.methods_available}""" ) @@ -870,7 +870,7 @@ def __getattr__(self, method_or_resource): class GoogleAPI: """ Creetes a representation of Google API given a discovery document - + Arguments: discovery_document (dict): A discovery document @@ -946,7 +946,7 @@ def __getattr__(self, method_or_resource) -> Resource: Returns resources from an API Note: - + This method will first check in resources then will check in methods. Arguments: @@ -981,8 +981,8 @@ def __getattr__(self, method_or_resource) -> Resource: ) raise AttributeError( f"""Resource/Method {method_or_resource} doesn't exist. - Check: {documentation_link} for more info. - \nAvailable resources are: + Check: {documentation_link} for more info. + \nAvailable resources are: {self.resources_available}\n Available methods are {self.methods_available}""" ) @@ -1010,14 +1010,14 @@ def __getitem__(self, k): >>> google_service['documentationLink'] - 'https://developers.google.com/books/docs/v1/getting_started' - + 'https://developers.google.com/books/docs/v1/getting_started' + >>> google_service['oauth2']['scopes'] https://www.googleapis.com/auth/books: { - + description: "Manage your books" - + } Returns: diff --git a/aiogoogle/sessions/abc.py b/aiogoogle/sessions/abc.py index b952a85..997ac27 100644 --- a/aiogoogle/sessions/abc.py +++ b/aiogoogle/sessions/abc.py @@ -38,13 +38,13 @@ async def send(self, *requests, timeout=None, full_res=False, session_factory=No Note: Given more than one request this method should return responses as a list. However if only given one, it will return a single response object - + Arguments: - + requests (aiogoogle.models.Request): Request objects from aiogoogle.models - + timeout (int): Total timeout for *requests @@ -65,7 +65,7 @@ async def send(self, *requests, timeout=None, full_res=False, session_factory=No * Session factory that creates a session that will handle pagination, resumable uploads etc. - * Defaults to ``self.__class__`` + * Defaults to ``self.__class__`` Returns: diff --git a/aiogoogle/validate.py b/aiogoogle/validate.py index e3639e6..b6acff3 100644 --- a/aiogoogle/validate.py +++ b/aiogoogle/validate.py @@ -297,7 +297,7 @@ def validate_type(instance, schema, schema_name=None): if type_validator_name not in JSON_PYTHON_TYPE_MAPPING: warnings.warn( f"""\n\nUnknown type: {type_validator_name} found.\n\nSkipping type checks for {instance} - against this schema:\n\n{schema}\n\nPlease create an + against this schema:\n\n{schema}\n\nPlease create an issue @ https://github.com/omarryhan/aiogoogle and report this warning msg.""" ) return @@ -316,7 +316,7 @@ def validate_format(instance, schema, schema_name=None): if format_validator_name not in KNOWN_FORMATS: warnings.warn( f"""\n\nUnknown format: {format_validator_name} found.\n\nSkipping format checks for {instance} - against this schema:\n\n{schema}\n\nPlease create an + against this schema:\n\n{schema}\n\nPlease create an issue @ https://github.com/omarryhan/aiogoogle and report this warning msg.""" ) return @@ -428,7 +428,7 @@ def validate_object(): if not additional_properties: raise ValidationError( f""" - Invalid Schema: {str(schema)}. + Invalid Schema: {str(schema)}. Neither properties nor addiotional properties found in this schema""" ) props = {} diff --git a/docs/index.rst b/docs/index.rst index 8d875dc..c0c121c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -45,7 +45,7 @@ Google Account Setup 1. **Create a project:** `Google's APIs and Services dashboard `_. 2. **Enable an API:** `API Library `_. 3. **Create credentials:** `Credentials wizard `_. -4. **Pick an API:** `Google's APIs Explorer `_ +4. **Pick an API:** `Google's APIs Explorer `_ Authentication ===================== @@ -54,14 +54,14 @@ Google APIs can be called on behalf of 3 main principals: 1. **User account** 2. **Service account** -3. Anonymous principal by using: **API keys** +3. Anonymous principal by using: **API keys** User account -------------- -Should be used whenever the application wants to access information +Should be used whenever the application wants to access information tied to a Google user. -Google provides two main authorization/authentication strategies that will +Google provides two main authorization/authentication strategies that will enable your application act on behalf of a user account: 1. **OAuth2** @@ -75,11 +75,11 @@ act on behalf of a user. It isn't designed to identify who the user is, rather only defines what a client (the app) can access. OAuth2 has 4 main flows. The most popular of them and the only one supported by -Google is `Authorization Code Flow `_. +Google is `Authorization Code Flow `_. There are **3** main parties involved in this flow: -1. **User**: +1. **User**: - represented as `UserCreds `__. 2. **Client**: - represented as `ClientCreds `__. @@ -153,7 +153,7 @@ If you want to integrate OAuth2 in an existing web app, or use it on many users grant = request.args.get('code'), client_creds = CLIENT_CREDS ) - # Here, you should store full_user_creds in a db. Especially the refresh token and access token. + # Here, you should store full_user_creds in a db. Especially the refresh token and access token. return response.json(full_user_creds) else: @@ -171,16 +171,16 @@ If you want to integrate OAuth2 in an existing web app, or use it on many users OpenID Connect ^^^^^^^^^^^^^^^^^^^ -OpenID Connect is an authentication layer built on top of OAuth2 -(an authorization framework). This method should be used when the client +OpenID Connect is an authentication layer built on top of OAuth2 +(an authorization framework). This method should be used when the client (the app) wants to identify the user i.e. authenticate them. -Since OpenID connect is a superset of OAuth2, this method will +Since OpenID connect is a superset of OAuth2, this method will also give the client the authorization needed to edit resources of the user. -In more practical terms, using OAuth2 alone will only return you a token -that can be used to access the data with the scope that the app requested. +In more practical terms, using OAuth2 alone will only return you a token +that can be used to access the data with the scope that the app requested. Using OpenIDConnect will return the same access token as with OAuth2 **plus** -an ID token JWT of the user. This ID token JWT will +an ID token JWT of the user. This ID token JWT will contain "claims" about the user which your app will need to properly know who they are. Here's an `example `__ of how an ID token JWT should look like. @@ -301,12 +301,12 @@ Service account ----------------------------- A service account is a special kind of account that belongs to an application -or a virtual machine (VM) instance but not a person. +or a virtual machine (VM) instance but not a person. They are intended for scenarios where your application needs to -access resources or perform actions on its own, +access resources or perform actions on its own, such as running App Engine apps or interacting with Compute Engine instances. -There are a couple of authentication/authorization methods you +There are a couple of authentication/authorization methods you can use with service accounts. We'll only concern ourselves with the ones that will grant us access to Google APIs and not for any other purpose e.g. communicating with other servers on a different cloud, @@ -316,7 +316,7 @@ OAuth2 ^^^^^^^^^^^^^ OAuth2 is the most commonly used service account authorization method and the only one implemented by Aiogoogle. -There are a couple of ways you can access Google APIs using OAuth2 +There are a couple of ways you can access Google APIs using OAuth2 tokens for service accounts: **1. By passing a user managed service account key:** @@ -458,7 +458,7 @@ Discovery Service Most of Google's public APIs are documented/discoverable by a single API called the Discovery Service. -Google's Discovery Serivce provides machine readable specifications known as discovery documents +Google's Discovery Serivce provides machine readable specifications known as discovery documents (similar to `Swagger/OpenAPI `_). `e.g. Google Books `_. ``Aiogoogle`` is a Pythonic wrapper for discovery documents. @@ -526,7 +526,7 @@ This is what the JSON representation of the discovery document we downloaded loo `Full reference: `_. -You don't have to worry about most of this. +You don't have to worry about most of this. What's important to understand right now is that a discovery service is just a way to specify the **resources** and **methods** of an API. **What are resources and methods?** @@ -605,7 +605,7 @@ Let's see what this method does >>> list_url['description'] "Retrieves a list of URLs shortened by a user." - + Cool, now let's see the optional parameters that this method accepts .. code-block:: python3 @@ -652,7 +652,7 @@ We can inspect the URL of the request by typing: .. code-block:: python3 >>> request.url - + 'https://www.googleapis.com/url/history?start_token=a_start_token&key=a_secret_key' Browse an API - Manually @@ -669,7 +669,7 @@ Sometimes it's easier to browse a discovery document manually instead of doing i https://www.googleapis.com/discovery/v1/apis/{api}/{version}/rest e.g. - + https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest 3. You'll then get a human readable JSON document with a structure similar to the one you've seen `above `_. @@ -750,7 +750,7 @@ Send Requests Concurrently json=dict( longUrl=long_url[0] ), - + url_shortener.url.insert( json=dict( longUrl=long_url[1] @@ -811,7 +811,7 @@ Send As API key "data": { "translations": [ { - "translatedText": "Aiogoogle est terribilis!", + "translatedText": "Aiogoogle est terribilis!", # Google probably meant "awesomelis", but whatever.. "detectedSourceLanguage": "en" } @@ -986,7 +986,7 @@ Upload a File to Google Drive drive_v3.files.create(upload_file=path) ) asyncio.run(upload_file('/home/aiogoogle/Documents/my_cool_gif.gif/')) - + Upload a File to Google Drive using an AsyncIterable ----------------------------------------------------- @@ -997,7 +997,7 @@ Full example `here