Module presalytics.client.api
Expand source code Browse git
import os
import cgi
import webbrowser
import time
import requests
import urllib.parse
import importlib.util
import logging
import json
import environs
import wsgi_microservice_middleware
import functools
import six
import mimetypes
import typing
import io
import time
import presalytics
import presalytics.lib.exceptions
import presalytics.lib.constants as cnst
import presalytics.client.auth
import presalytics.client.oidc
import presalytics.client.presalytics_ooxml_automation.api_client
import presalytics.client.presalytics_story.api_client
import presalytics.client.presalytics_doc_converter.api_client
from uuid import uuid4
from werkzeug.datastructures import FileStorage
logger = logging.getLogger(__name__)
env = environs.Env()
class Client(object):
""" Class for interacting with Presalytics API endpoints
The Client class creates a simple interface for user to interactive with the
Presalytics API and is the primary building block for user-built automation of stories,
dashboards, and interactive presentations.
A client instance wraps python functions around Presalytics API endpoints and
manages user authentication. On initialization, he client checks the status of
a user authentication the expiry of their refresh an access tokens. When needed,
the client will open a browser to prompt the user to login at the presalytics.io
login page (or raise an `presalytics.lib.exceptions.InvalidTokenException` when
`delegate_login` is `True`).
After authenication, users can call the methods bound to the story, ooxml_automation,
and doc_converter attributes to make calls in into the Presalytics API.
*A note for server-side development*:
The client class can automatically cache tokens in a file called
"token.json", located in the python's current working directory. This is done so
users running scripts accross multiple client instances do not have to acquire a new token
every time an API call is made. If building a client to operate in a multi-user environment,
this behavior should be turned off so that one user cannot not pull one another's tokens.
To do this, ensure the following parameters are pass to the configuration either
via initialization or in a `presalytics.CONFIG` file:
cache_tokens = False,
delegate_login = True
When delegate login is True, the client assumes that the application creating
instances of the client object will handle user authentication. The simplest way
to do this is to pass a token to the client via the "token" keyword argument.
Parameters
----------
username : str, optional
Defaults to None. The user's Presalytics API username. This keyword will take precedence over a passed to the client
via `presalytics.CONFIG`. The username must either be present in `presalytics.CONFIG` or be passed in
via keyword, otherwise the client will raise a `presalytics.lib.exceptions.MissingConfigException`.
password : str, optional
Defaults to None. The user's Presalytics API password. This useful for quickly testing scripts, but in most
scenario users should not be passing plaintext into the client via this keyword. In a secure, single-user
environment, passwords are better placed in the `presalytics.CONFIG` object for reuseability. A more secure
is to leave passwords out of the configuration, keep `delegate_login` = `False`, and acquire tokens via the browser.
delegate_login : bool, optional
Defaults to False. Indicates whether the client would redirect to a browser to
acquire an API token. If `DELEGATE_LOGIN` is `True`, when the `presalytics.client.api.Client` does not have
access to a valid API token, the client will raise a `presalytics.lib.exceptions.InvalidTokenException`.
The default operation will automatically open a new browser tab to acquire a new token
via website client from the presalytics.io login page. Putting this setting to True is
useful for server-side development.
token : dict, optional
Defaults to None. A dictionary contain information about tokens acquire from auth.presalytics.io. The
dictionary must contain an `access_token`, a `refresh_token`, and entries contiaing information about token expiry.
Token expiry information can either passed in ISO 8601 formatted string with a UTC offset as dictionary keys
`access_token_expire_time` and `refresh_token_expire_time` or an integer in seconds with the corresponding
dictionary keys`expires_in` and `refresh_expires_in`.
if the `dict` passed in via this keywork does is not have the correct entries, the client will
raise an `presalytics.lib.exceptions.InvalidTokenException`.
cache_tokens : bool, optional
Defaults to False. Toggles whether or the client should cache its acquired tokens in file called "token.json"
in the current working directory. Minimizes the number of times a user is required to login. Set to False
in multi-user environments.
Attributes
----------
direct_grant : bool
Indicates whether an token will be acquire via the "direct_grant" OpenID Connect flow. Usually indicates
whether the user has supplied a passwork to the client either through `presalytics.CONFIG` ro
during object initialization.
doc_converter : presalytics.client.presalytics_doc_converter.api.default_api.DefaultApi
Interface to the Presalytics API Doc Converter service. The object contains methods that enable
the client to make api calls that return deserialized objects from the Presalytics API,
simplying user and developer interaction with the Presaltytics API. API calls can be generated
as follows:
client = presalytics.Client()
api_obj = client.doc_converter.{operation_id}(*args)
where `{operation_id}` is the `operationId` assocated with the endpoint specified the [Doc Converter
Service OpenAPI Contract](https://presalytics.io/docs/api-specifications/doc-converter/) , and *args
are the corresponding arguments that are passed to the method. A complete list of the avialable
methods is shown on the `presalytics.client.presalytics_doc_converter.api.default_api.DefaultApi` object.
*Note*:
This attribute contains automatically generated methods via
the [OpenAPI generator](https://github.com/OpenAPITools/openapi-generator). The
`presalytics.client.presalytics_doc_converter.api.default_api.DefaultApi` has been passed an an `api_client`
keyword argument with an instance of `presalytics.client.api.DocConverterApiClientWithAuth`, which adds
an authentication and request processing middleware layer to the default sub package
built via code generatation.
ooxml_automation : presalytics.client.presalytics_ooxml_automation.api.default_api.DefaultApi
Interface to the Presalytics API Ooxml Automation service. The object contains methods that enable
the client to make api calls that return deserialized objects from the Presalytics API,
simplying user and developer interaction with the Presaltytics API. API calls can be generated
as follows:
client = presalytics.Client()
api_obj = client.ooxml_automation.{operation_id}(*args)
where `{operation_id}` is the `operationId` assocated with the endpoint specified the [Ooxml Automation
Service OpenAPI Contract](https://presalytics.io/docs/api-specifications/ooxml-automation/) , and *args
are the corresponding arguments that are passed to the method. A complete list of the avialable
methods is shown on the `presalytics.client.presalytics_ooxml_automation.api.default_api.DefaultApi` object.
*Note*:
This attribute contains automatically generated methods via
the [OpenAPI generator](https://github.com/OpenAPITools/openapi-generator). The
`presalytics.client.presalytics_ooxml_automation.api.default_api.DefaultApi` has been passed an an `api_client`
keyword argument with an instance of `presalytics.client.api.OoxmlAutomationApiClientWithAuth`, which adds
an authentication and request processing middleware layer to the default sub package
built via code generatation.
story : presalytics.client.presalytics_story.api.default_api.DefaultApi
Interface to the Presalytics API Ooxml Automation service. The object contains methods that enable
the client to make api calls that return deserialized objects from the Presalytics API,
simplying user and developer interaction with the Presaltytics API. API calls can be generated
as follows:
client = presalytics.Client()
api_obj = client.story.{operation_id}(*args)
where `{operation_id}` is the `operationId` assocated with the endpoint specified the [Ooxml Automation
Service OpenAPI Contract](https://presalytics.io/docs/api-specifications/story/) , and *args
are the corresponding arguments that are passed to the method. A complete list of the avialable
methods is shown on the `presalytics.client.presalytics_story.api.default_api.DefaultApi` object.
*Note*:
This attribute contains automatically generated methods via
the [OpenAPI generator](https://github.com/OpenAPITools/openapi-generator). The
`presalytics.client.presalytics_story.api.default_api.DefaultApi` has been passed an an `api_client`
keyword argument with an instance of `presalytics.client.api.StoryApiClientWithAuth`, which adds
an authentication and request processing middleware layer to the default sub package
built via code generatation.
client_id : str
The client_id that is used OpenID Connect login. Defaults to "python-client".
client_secret : str, optional
The client_secret used during OpenID Connect login. Useful `confidential_client` is True.
confidential_client : bool
Indicates whether a this client can obtain tokens from auth.presalytics.io without a user under
OpenID Connect grant type "confidential_client". Requires a `client_secret`. Default is False.
oidc : `presalytics.client.oidc.OidcClient`
A middleware class to help acquire and validate tokens from login.presalytics.io.
token_util : `presalytics.client.auth.TokenUtil`
A handler for managing an caching tokens acquired from auth.presalytics.io.
site_host : str
The login site host for acquiring tokens. Set from `presalytics.CONFIG` with keyword `["SITE"]["HOST"]`.
Defaults to https://presalytics.io.
redirect_uri : str
Useful if implementing authorization code flow for and OpenID Connect client. Redirect URIs must
be approved by Presalytics API devops for use in client applications. Set from Set from
`presalytics.CONFIG` with keyword `["REDIRECT_URI"]`. Defaults to https://presalytics.io/user/login-success.
login_sleep_interval : int
The duration (in seconds) between attempts to acquire a token after browser-based authentication. Defaults
to 5 seconds.
login_timeout : int
Defaults to 60 seconds. The amount of time the client will attempt to acquire a token after the
https://presalytics.io authenicates a user. Raises a `presalytics.lib.exceptions.LoginTimeout`
if the user has not authenticated by the time the interval has expired.
"""
def __init__(
self,
username=None,
password=None,
delegate_login=False,
token=None,
cache_tokens=False,
client_id=None,
client_secret=None,
**kwargs):
if username:
self.username = username
else:
try:
self.username = presalytics.CONFIG['USERNAME']
except KeyError:
if token:
self.username = None
else:
if not client_secret:
raise presalytics.lib.exceptions.MissingConfigException("when not passing tokens directly, a clien must have either a client_secrect or a username")
try:
if password:
self.password = password
else:
self.password = presalytics.CONFIG['PASSWORD']
self.direct_grant = True
except KeyError:
self.password = None
self.direct_grant = False
try:
if client_id:
self.client_id = client_id
else:
self.client_id = presalytics.CONFIG['CLIENT_ID']
except KeyError:
self.client_id = cnst.DEFAULT_CLIENT_ID
try:
if client_secret:
self.client_secret = client_secret
else:
self.client_secret = presalytics.CONFIG['CLIENT_SECRET']
self.confidential_client = True
except KeyError:
self.client_secret = None
self.confidential_client = False
try:
self.site_host = presalytics.CONFIG["HOSTS"]["SITE"]
except KeyError:
self.site_host = cnst.SITE_HOST
try:
self.redirect_uri = presalytics.CONFIG["REDIRECT_URI"]
except KeyError:
self.redirect_uri = cnst.REDIRECT_URI
if delegate_login or presalytics.CONFIG.get("DELEGATE_LOGIN", False):
self._delegate_login = True
else:
self._delegate_login = False
self.oidc = presalytics.client.oidc.OidcClient(
client_id=self.client_id,
client_secret=self.client_secret
)
if presalytics.CONFIG.get("CACHE_TOKENS", None):
cache_tokens = presalytics.CONFIG.get("CACHE_TOKENS")
self.token_util = presalytics.client.auth.TokenUtil(token_cache=cache_tokens)
if token:
# Assume if token is passed as string, then it's an access token
if isinstance(token, str):
self.token_util.token = {"access_token": token}
# if token is a dictionary with an 'access_token_expire_time' key, it's previous been processed / deserialized
elif token.get('access_token_expire_time', None):
self.token_util.token = token
# if token has an 'expires_in' key, if has not been deserialized
elif token.get('expires_in', None):
self.token_util.process_token(token)
else:
raise presalytics.lib.exceptions.InvalidTokenException(message="Unknown token format.")
if self.token_util.token_cache:
self.token_util._put_token_file()
if not self._delegate_login:
self.token_util.token = self.refresh_token()
doc_converter_api_client = DocConverterApiClientWithAuth(self, **kwargs)
self.doc_converter = presalytics.client.presalytics_doc_converter.DefaultApi(api_client=doc_converter_api_client)
ooxml_automation_api_client = OoxmlAutomationApiClientWithAuth(self, **kwargs)
self.ooxml_automation = presalytics.client.presalytics_ooxml_automation.DefaultApi(api_client=ooxml_automation_api_client)
story_api_client = StoryApiClientWithAuth(self, **kwargs)
self.story = presalytics.client.presalytics_story.DefaultApi(api_client=story_api_client)
def login(self):
"""
Triggers a an attempt to acquire an API token based on the the client configuration
"""
if self.direct_grant:
token = self.oidc.token(username=self.username, password=self.password)
else:
token = self.oidc.token(username=self.username)
self.token_util.process_token(token)
return self.token_util.token
def refresh_token(self):
"""
Obtains a new access token if the access token is expired. if refresh token is expired,
this method prompt user to re-authenticate when `delegate_login` is `False` or raise
an `presalytics.lib.exceptions.InvalidTokenException` when `deletegate_login` is True.
"""
if self.token_util.is_api_access_token_expired():
if self.token_util.token.get('refresh_token', None) and self.client_secret:
refresh_token = self.token_util.token["refresh_token"]
token = self.oidc.refresh_token(refresh_token)
self.token_util.process_token(token)
logger.debug("Refresh token granted successfully.")
else:
if self.direct_grant:
token = self.oidc.token(username=self.username, password=self.password)
elif self.confidential_client:
token = self.oidc.client_credentials_token()
elif self._delegate_login:
raise presalytics.lib.exceptions.ApiError("Unauthorized. Token has expired", status_code=401)
else:
token = self.oidc.token(username=self.username)
self.token_util.process_token(token)
if self.token_util.token_cache:
self.token_util._put_token_file()
return self.token_util.token
def get_auth_header(self):
"""
Creates a JWT Bearer Authorization token header
Returns
----------
A `dict` authorization crediential to be attached to an API request
"""
self.refresh_token()
auth_header = {
"Authorization": "Bearer " + self.token_util.token["access_token"]
}
return auth_header
def get_request_id_header(self):
"""
Creates an 'X-Request-Id' token header for tracing requests through Presalytics API
services. If deployed alongside the [WSGI Microservice Middleware](https://github.com/presalytics/WSGI-Microservice-Middleware)
package, this method will pull the request id from the call stack.
Returns
----------
A `dict` header representation with an 'X-Request-Id' key to be attached to an API request
"""
current_request_id = wsgi_microservice_middleware.current_request_id()
if not current_request_id:
current_request_id = str(uuid4())
header = {
"X-Request-Id": current_request_id
}
return header
def download_file(self, story_id, ooxml_automation_id, download_folder=None, filename=None, **kwargs):
"""
Downloads an updated Ooxml Automation file and places the file in a designated folder
Parameters
---------
story : str
The id of the Presalytics Story API object that manages access to document
ooxml_automation_id : str
The id of the Presalytics API Ooxml Automation service object that you want to download
download_folder : str, optional
The filepath to the local directory that you want to download the file to. Defaults to the
current working directory.
filename: str, optional
The name of the downloaded file. Defaults to the original filename the the object was created.
"""
response, status, headers = self.story.story_id_file_ooxmlautomationid_get_with_http_info(story_id, ooxml_automation_id, _preload_content=False)
if download_folder is None:
download_folder = os.getcwd()
if filename is None:
cd_header = headers.get('Content-Disposition')
_, params = cgi.parse_header(cd_header)
filename = params["filename"]
filepath = os.path.join(download_folder, filename)
with open(filepath, 'wb') as f:
f.write(response.data)
def get_client_info(self):
"""
Convenience method returning information about this client to pass to downstream objects, e.g.,
components and new client instances
Returns
----------
A dictionary containing instances values:
- token: self.token_util.token
- client_id: self.client_id
- cache_tokens: self.token_util.token_cache
- delegate_login: self.delegate login
"""
return {
"token": self.token_util.token,
"client_id": self.client_id,
"cache_tokens": self.token_util.token_cache,
"delegate_login": self._delegate_login
}
STATUS_REPOLL_SECONDS = 2
STATUS_REPOLL_MAX_CYCLES = 20
def upload_file_and_await_outline(self,
file: typing.Union[FileStorage, str],
include_relationships=True,
status_repoll_seconds: int = None,
repoll_max_cycles: int = None):
""" Useful for testing """
if type(file) is str:
content_type = mimetypes.guess_type(file, False)[0] # type: ignore
with open(file, 'rb') as f: # type: ignore
stream = io.BytesIO(f.read())
file = FileStorage(
stream=stream, # type: ignore
filename=file, # type: ignore
content_type=content_type,
content_length=stream.__sizeof__()
)
if not status_repoll_seconds:
status_repoll_seconds = self.STATUS_REPOLL_SECONDS
if not repoll_max_cycles:
repoll_max_cycles = self.STATUS_REPOLL_MAX_CYCLES
story = self.story.story_post_file(file=file)
self.await_outline(story.id)
return self.story.story_id_get(story.id, include_outline=True, include_relationships=include_relationships)
def await_outline(self,
story_id,
status_repoll_seconds: int = None,
repoll_max_cycles: int = None):
task_running = True
repoll_cycle_count = 0
if not status_repoll_seconds:
status_repoll_seconds = self.STATUS_REPOLL_SECONDS
if not repoll_max_cycles:
repoll_max_cycles = self.STATUS_REPOLL_MAX_CYCLES
while task_running:
status, status_code, _ = self.story.story_id_status_get_with_http_info(story_id)
if status_code == 204:
task_running = False
elif status_code == 200:
if status.status == "SUCCESS":
task_running = False
elif repoll_cycle_count >= repoll_max_cycles:
raise presalytics.lib.exceptions.ApiError(message="Error occured while uploading file", status_code=500)
else:
logger.info("Story creation task still running. Rechecking status in {0} seconds".format(status_repoll_seconds))
time.sleep(status_repoll_seconds)
repoll_cycle_count += 1
return self.story.story_id_outline_get(story_id)
class DocConverterApiClientWithAuth(presalytics.client.auth.AuthenticationMixIn, presalytics.client.presalytics_doc_converter.api_client.ApiClient):
"""
Wraps `presalytics.client.presalytics_doc_converter.api_client.ApiClient` with
`presalytics.client.auth.AuthenticationMixIn` middleware
"""
def __init__(self, parent: Client, **kwargs):
presalytics.client.auth.AuthenticationMixIn.__init__(self, parent, **kwargs)
presalytics.client.presalytics_doc_converter.api_client.ApiClient.__init__(self)
self.update_configuration()
@property
def api_name(self):
return 'doc-converter'
class OoxmlAutomationApiClientWithAuth(presalytics.client.auth.AuthenticationMixIn, presalytics.client.presalytics_ooxml_automation.api_client.ApiClient):
"""
Wraps `presalytics.client.presalytics_ooxml_automation.api_client.ApiClient` with
`presalytics.client.auth.AuthenticationMixIn` middleware
"""
def __init__(self, parent: Client, **kwargs):
presalytics.client.auth.AuthenticationMixIn.__init__(self, parent, **kwargs)
presalytics.client.presalytics_ooxml_automation.api_client.ApiClient.__init__(self)
self.update_configuration()
@property
def api_name(self):
return 'ooxml-automation'
class StoryApiClientWithAuth(presalytics.client.auth.AuthenticationMixIn, presalytics.client.presalytics_story.api_client.ApiClient):
"""
Wraps `presalytics.client.presalytics_story.api_client.ApiClient` with
`presalytics.client.auth.AuthenticationMixIn` middleware
"""
def __init__(self, parent: Client, **kwargs):
presalytics.client.auth.AuthenticationMixIn.__init__(self, parent, **kwargs)
presalytics.client.presalytics_story.api_client.ApiClient.__init__(self)
self.update_configuration()
@property
def api_name(self):
return 'story'
@functools.lru_cache(maxsize=None)
def get_client():
"""
Caches a client instance for default parameters set in `presalytics.CONFIG`.
DO NOT use in server-side operation
"""
client = presalytics.Client()
return client
Functions
def get_client()
-
Caches a client instance for default parameters set in
CONFIG
.DO NOT use in server-side operation
Expand source code Browse git
@functools.lru_cache(maxsize=None) def get_client(): """ Caches a client instance for default parameters set in `presalytics.CONFIG`. DO NOT use in server-side operation """ client = presalytics.Client() return client
Classes
class Client (username=None, password=None, delegate_login=False, token=None, cache_tokens=False, client_id=None, client_secret=None, **kwargs)
-
Class for interacting with Presalytics API endpoints
The Client class creates a simple interface for user to interactive with the Presalytics API and is the primary building block for user-built automation of stories, dashboards, and interactive presentations.
A client instance wraps python functions around Presalytics API endpoints and manages user authentication. On initialization, he client checks the status of a user authentication the expiry of their refresh an access tokens. When needed, the client will open a browser to prompt the user to login at the presalytics.io login page (or raise an
InvalidTokenException
whendelegate_login
isTrue
).After authenication, users can call the methods bound to the story, ooxml_automation, and doc_converter attributes to make calls in into the Presalytics API.
A note for server-side development:
The client class can automatically cache tokens in a file called "token.json", located in the python's current working directory. This is done so users running scripts accross multiple client instances do not have to acquire a new token every time an API call is made. If building a client to operate in a multi-user environment, this behavior should be turned off so that one user cannot not pull one another's tokens. To do this, ensure the following parameters are pass to the configuration either via initialization or in a
CONFIG
file:cache_tokens = False, delegate_login = True
When delegate login is True, the client assumes that the application creating instances of the client object will handle user authentication. The simplest way to do this is to pass a token to the client via the "token" keyword argument.
Parameters
username
:str
, optional- Defaults to None.
The user's Presalytics API username.
This keyword will take precedence over a passed to the client
via
CONFIG
. The username must either be present inCONFIG
or be passed in via keyword, otherwise the client will raise aMissingConfigException
. password
:str
, optional- Defaults to None.
The user's Presalytics API password.
This useful for quickly testing scripts, but in most
scenario users should not be passing plaintext into the client via this keyword.
In a secure, single-user
environment, passwords are better placed in the
CONFIG
object for reuseability. A more secure is to leave passwords out of the configuration, keepdelegate_login
=False
, and acquire tokens via the browser. delegate_login
:bool
, optional- Defaults to False.
Indicates whether the client would redirect to a browser to
acquire an API token. If
DELEGATE_LOGIN
isTrue
, when theClient
does not have access to a valid API token, the client will raise aInvalidTokenException
. The default operation will automatically open a new browser tab to acquire a new token via website client from the presalytics.io login page. Putting this setting to True is useful for server-side development. token
:dict
, optional-
Defaults to None. A dictionary contain information about tokens acquire from auth.presalytics.io. The dictionary must contain an
access_token
, arefresh_token
, and entries contiaing information about token expiry.Token expiry information can either passed in ISO 8601 formatted string with a UTC offset as dictionary keys
access_token_expire_time
andrefresh_token_expire_time
or an integer in seconds with the corresponding dictionary keysexpires_in
andrefresh_expires_in
.if the
dict
passed in via this keywork does is not have the correct entries, the client will raise anInvalidTokenException
. cache_tokens
:bool
, optional- Defaults to False. Toggles whether or the client should cache its acquired tokens in file called "token.json" in the current working directory. Minimizes the number of times a user is required to login. Set to False in multi-user environments.
Attributes
direct_grant
:bool
- Indicates whether an token will be acquire via the "direct_grant" OpenID Connect flow.
Usually indicates
whether the user has supplied a passwork to the client either through
CONFIG
ro during object initialization. doc_converter
:DefaultApi
-
Interface to the Presalytics API Doc Converter service. The object contains methods that enable the client to make api calls that return deserialized objects from the Presalytics API, simplying user and developer interaction with the Presaltytics API. API calls can be generated as follows:
client = presalytics.Client() api_obj = client.doc_converter.{operation_id}(*args)
where
{operation_id}
is theoperationId
assocated with the endpoint specified the Doc Converter Service OpenAPI Contract , and *args are the corresponding arguments that are passed to the method. A complete list of the avialable methods is shown on theDefaultApi
object.Note: This attribute contains automatically generated methods via the OpenAPI generator. The
DefaultApi
has been passed an anapi_client
keyword argument with an instance ofDocConverterApiClientWithAuth
, which adds an authentication and request processing middleware layer to the default sub package built via code generatation. ooxml_automation
:DefaultApi
-
Interface to the Presalytics API Ooxml Automation service. The object contains methods that enable the client to make api calls that return deserialized objects from the Presalytics API, simplying user and developer interaction with the Presaltytics API. API calls can be generated as follows:
client = presalytics.Client() api_obj = client.ooxml_automation.{operation_id}(*args)
where
{operation_id}
is theoperationId
assocated with the endpoint specified the Ooxml Automation Service OpenAPI Contract , and *args are the corresponding arguments that are passed to the method. A complete list of the avialable methods is shown on theDefaultApi
object.Note: This attribute contains automatically generated methods via the OpenAPI generator. The
DefaultApi
has been passed an anapi_client
keyword argument with an instance ofOoxmlAutomationApiClientWithAuth
, which adds an authentication and request processing middleware layer to the default sub package built via code generatation. story
:DefaultApi
-
Interface to the Presalytics API Ooxml Automation service. The object contains methods that enable the client to make api calls that return deserialized objects from the Presalytics API, simplying user and developer interaction with the Presaltytics API. API calls can be generated as follows:
client = presalytics.Client() api_obj = client.story.{operation_id}(*args)
where
{operation_id}
is theoperationId
assocated with the endpoint specified the Ooxml Automation Service OpenAPI Contract , and *args are the corresponding arguments that are passed to the method. A complete list of the avialable methods is shown on theDefaultApi
object.Note: This attribute contains automatically generated methods via the OpenAPI generator. The
DefaultApi
has been passed an anapi_client
keyword argument with an instance ofStoryApiClientWithAuth
, which adds an authentication and request processing middleware layer to the default sub package built via code generatation. client_id
:str
- The client_id that is used OpenID Connect login. Defaults to "python-client".
client_secret
:str
, optional- The client_secret used during OpenID Connect login.
Useful
confidential_client
is True. confidential_client
:bool
- Indicates whether a this client can obtain tokens from auth.presalytics.io without a user under
OpenID Connect grant type "confidential_client".
Requires a
client_secret
. Default is False. oidc
:presalytics.client.oidc.OidcClient
- A middleware class to help acquire and validate tokens from login.presalytics.io.
token_util
:presalytics.client.auth.TokenUtil
- A handler for managing an caching tokens acquired from auth.presalytics.io.
site_host
:str
- The login site host for acquiring tokens.
Set from
CONFIG
with keyword["SITE"]["HOST"]
. Defaults to https://presalytics.io. redirect_uri
:str
- Useful if implementing authorization code flow for and OpenID Connect client.
Redirect URIs must
be approved by Presalytics API devops for use in client applications. Set from Set from
CONFIG
with keyword["REDIRECT_URI"]
. Defaults to https://presalytics.io/user/login-success. login_sleep_interval
:int
- The duration (in seconds) between attempts to acquire a token after browser-based authentication. Defaults to 5 seconds.
login_timeout
:int
- Defaults to 60 seconds.
The amount of time the client will attempt to acquire a token after the
https://presalytics.io authenicates a user. Raises a
LoginTimeout
if the user has not authenticated by the time the interval has expired.
Expand source code Browse git
class Client(object): """ Class for interacting with Presalytics API endpoints The Client class creates a simple interface for user to interactive with the Presalytics API and is the primary building block for user-built automation of stories, dashboards, and interactive presentations. A client instance wraps python functions around Presalytics API endpoints and manages user authentication. On initialization, he client checks the status of a user authentication the expiry of their refresh an access tokens. When needed, the client will open a browser to prompt the user to login at the presalytics.io login page (or raise an `presalytics.lib.exceptions.InvalidTokenException` when `delegate_login` is `True`). After authenication, users can call the methods bound to the story, ooxml_automation, and doc_converter attributes to make calls in into the Presalytics API. *A note for server-side development*: The client class can automatically cache tokens in a file called "token.json", located in the python's current working directory. This is done so users running scripts accross multiple client instances do not have to acquire a new token every time an API call is made. If building a client to operate in a multi-user environment, this behavior should be turned off so that one user cannot not pull one another's tokens. To do this, ensure the following parameters are pass to the configuration either via initialization or in a `presalytics.CONFIG` file: cache_tokens = False, delegate_login = True When delegate login is True, the client assumes that the application creating instances of the client object will handle user authentication. The simplest way to do this is to pass a token to the client via the "token" keyword argument. Parameters ---------- username : str, optional Defaults to None. The user's Presalytics API username. This keyword will take precedence over a passed to the client via `presalytics.CONFIG`. The username must either be present in `presalytics.CONFIG` or be passed in via keyword, otherwise the client will raise a `presalytics.lib.exceptions.MissingConfigException`. password : str, optional Defaults to None. The user's Presalytics API password. This useful for quickly testing scripts, but in most scenario users should not be passing plaintext into the client via this keyword. In a secure, single-user environment, passwords are better placed in the `presalytics.CONFIG` object for reuseability. A more secure is to leave passwords out of the configuration, keep `delegate_login` = `False`, and acquire tokens via the browser. delegate_login : bool, optional Defaults to False. Indicates whether the client would redirect to a browser to acquire an API token. If `DELEGATE_LOGIN` is `True`, when the `presalytics.client.api.Client` does not have access to a valid API token, the client will raise a `presalytics.lib.exceptions.InvalidTokenException`. The default operation will automatically open a new browser tab to acquire a new token via website client from the presalytics.io login page. Putting this setting to True is useful for server-side development. token : dict, optional Defaults to None. A dictionary contain information about tokens acquire from auth.presalytics.io. The dictionary must contain an `access_token`, a `refresh_token`, and entries contiaing information about token expiry. Token expiry information can either passed in ISO 8601 formatted string with a UTC offset as dictionary keys `access_token_expire_time` and `refresh_token_expire_time` or an integer in seconds with the corresponding dictionary keys`expires_in` and `refresh_expires_in`. if the `dict` passed in via this keywork does is not have the correct entries, the client will raise an `presalytics.lib.exceptions.InvalidTokenException`. cache_tokens : bool, optional Defaults to False. Toggles whether or the client should cache its acquired tokens in file called "token.json" in the current working directory. Minimizes the number of times a user is required to login. Set to False in multi-user environments. Attributes ---------- direct_grant : bool Indicates whether an token will be acquire via the "direct_grant" OpenID Connect flow. Usually indicates whether the user has supplied a passwork to the client either through `presalytics.CONFIG` ro during object initialization. doc_converter : presalytics.client.presalytics_doc_converter.api.default_api.DefaultApi Interface to the Presalytics API Doc Converter service. The object contains methods that enable the client to make api calls that return deserialized objects from the Presalytics API, simplying user and developer interaction with the Presaltytics API. API calls can be generated as follows: client = presalytics.Client() api_obj = client.doc_converter.{operation_id}(*args) where `{operation_id}` is the `operationId` assocated with the endpoint specified the [Doc Converter Service OpenAPI Contract](https://presalytics.io/docs/api-specifications/doc-converter/) , and *args are the corresponding arguments that are passed to the method. A complete list of the avialable methods is shown on the `presalytics.client.presalytics_doc_converter.api.default_api.DefaultApi` object. *Note*: This attribute contains automatically generated methods via the [OpenAPI generator](https://github.com/OpenAPITools/openapi-generator). The `presalytics.client.presalytics_doc_converter.api.default_api.DefaultApi` has been passed an an `api_client` keyword argument with an instance of `presalytics.client.api.DocConverterApiClientWithAuth`, which adds an authentication and request processing middleware layer to the default sub package built via code generatation. ooxml_automation : presalytics.client.presalytics_ooxml_automation.api.default_api.DefaultApi Interface to the Presalytics API Ooxml Automation service. The object contains methods that enable the client to make api calls that return deserialized objects from the Presalytics API, simplying user and developer interaction with the Presaltytics API. API calls can be generated as follows: client = presalytics.Client() api_obj = client.ooxml_automation.{operation_id}(*args) where `{operation_id}` is the `operationId` assocated with the endpoint specified the [Ooxml Automation Service OpenAPI Contract](https://presalytics.io/docs/api-specifications/ooxml-automation/) , and *args are the corresponding arguments that are passed to the method. A complete list of the avialable methods is shown on the `presalytics.client.presalytics_ooxml_automation.api.default_api.DefaultApi` object. *Note*: This attribute contains automatically generated methods via the [OpenAPI generator](https://github.com/OpenAPITools/openapi-generator). The `presalytics.client.presalytics_ooxml_automation.api.default_api.DefaultApi` has been passed an an `api_client` keyword argument with an instance of `presalytics.client.api.OoxmlAutomationApiClientWithAuth`, which adds an authentication and request processing middleware layer to the default sub package built via code generatation. story : presalytics.client.presalytics_story.api.default_api.DefaultApi Interface to the Presalytics API Ooxml Automation service. The object contains methods that enable the client to make api calls that return deserialized objects from the Presalytics API, simplying user and developer interaction with the Presaltytics API. API calls can be generated as follows: client = presalytics.Client() api_obj = client.story.{operation_id}(*args) where `{operation_id}` is the `operationId` assocated with the endpoint specified the [Ooxml Automation Service OpenAPI Contract](https://presalytics.io/docs/api-specifications/story/) , and *args are the corresponding arguments that are passed to the method. A complete list of the avialable methods is shown on the `presalytics.client.presalytics_story.api.default_api.DefaultApi` object. *Note*: This attribute contains automatically generated methods via the [OpenAPI generator](https://github.com/OpenAPITools/openapi-generator). The `presalytics.client.presalytics_story.api.default_api.DefaultApi` has been passed an an `api_client` keyword argument with an instance of `presalytics.client.api.StoryApiClientWithAuth`, which adds an authentication and request processing middleware layer to the default sub package built via code generatation. client_id : str The client_id that is used OpenID Connect login. Defaults to "python-client". client_secret : str, optional The client_secret used during OpenID Connect login. Useful `confidential_client` is True. confidential_client : bool Indicates whether a this client can obtain tokens from auth.presalytics.io without a user under OpenID Connect grant type "confidential_client". Requires a `client_secret`. Default is False. oidc : `presalytics.client.oidc.OidcClient` A middleware class to help acquire and validate tokens from login.presalytics.io. token_util : `presalytics.client.auth.TokenUtil` A handler for managing an caching tokens acquired from auth.presalytics.io. site_host : str The login site host for acquiring tokens. Set from `presalytics.CONFIG` with keyword `["SITE"]["HOST"]`. Defaults to https://presalytics.io. redirect_uri : str Useful if implementing authorization code flow for and OpenID Connect client. Redirect URIs must be approved by Presalytics API devops for use in client applications. Set from Set from `presalytics.CONFIG` with keyword `["REDIRECT_URI"]`. Defaults to https://presalytics.io/user/login-success. login_sleep_interval : int The duration (in seconds) between attempts to acquire a token after browser-based authentication. Defaults to 5 seconds. login_timeout : int Defaults to 60 seconds. The amount of time the client will attempt to acquire a token after the https://presalytics.io authenicates a user. Raises a `presalytics.lib.exceptions.LoginTimeout` if the user has not authenticated by the time the interval has expired. """ def __init__( self, username=None, password=None, delegate_login=False, token=None, cache_tokens=False, client_id=None, client_secret=None, **kwargs): if username: self.username = username else: try: self.username = presalytics.CONFIG['USERNAME'] except KeyError: if token: self.username = None else: if not client_secret: raise presalytics.lib.exceptions.MissingConfigException("when not passing tokens directly, a clien must have either a client_secrect or a username") try: if password: self.password = password else: self.password = presalytics.CONFIG['PASSWORD'] self.direct_grant = True except KeyError: self.password = None self.direct_grant = False try: if client_id: self.client_id = client_id else: self.client_id = presalytics.CONFIG['CLIENT_ID'] except KeyError: self.client_id = cnst.DEFAULT_CLIENT_ID try: if client_secret: self.client_secret = client_secret else: self.client_secret = presalytics.CONFIG['CLIENT_SECRET'] self.confidential_client = True except KeyError: self.client_secret = None self.confidential_client = False try: self.site_host = presalytics.CONFIG["HOSTS"]["SITE"] except KeyError: self.site_host = cnst.SITE_HOST try: self.redirect_uri = presalytics.CONFIG["REDIRECT_URI"] except KeyError: self.redirect_uri = cnst.REDIRECT_URI if delegate_login or presalytics.CONFIG.get("DELEGATE_LOGIN", False): self._delegate_login = True else: self._delegate_login = False self.oidc = presalytics.client.oidc.OidcClient( client_id=self.client_id, client_secret=self.client_secret ) if presalytics.CONFIG.get("CACHE_TOKENS", None): cache_tokens = presalytics.CONFIG.get("CACHE_TOKENS") self.token_util = presalytics.client.auth.TokenUtil(token_cache=cache_tokens) if token: # Assume if token is passed as string, then it's an access token if isinstance(token, str): self.token_util.token = {"access_token": token} # if token is a dictionary with an 'access_token_expire_time' key, it's previous been processed / deserialized elif token.get('access_token_expire_time', None): self.token_util.token = token # if token has an 'expires_in' key, if has not been deserialized elif token.get('expires_in', None): self.token_util.process_token(token) else: raise presalytics.lib.exceptions.InvalidTokenException(message="Unknown token format.") if self.token_util.token_cache: self.token_util._put_token_file() if not self._delegate_login: self.token_util.token = self.refresh_token() doc_converter_api_client = DocConverterApiClientWithAuth(self, **kwargs) self.doc_converter = presalytics.client.presalytics_doc_converter.DefaultApi(api_client=doc_converter_api_client) ooxml_automation_api_client = OoxmlAutomationApiClientWithAuth(self, **kwargs) self.ooxml_automation = presalytics.client.presalytics_ooxml_automation.DefaultApi(api_client=ooxml_automation_api_client) story_api_client = StoryApiClientWithAuth(self, **kwargs) self.story = presalytics.client.presalytics_story.DefaultApi(api_client=story_api_client) def login(self): """ Triggers a an attempt to acquire an API token based on the the client configuration """ if self.direct_grant: token = self.oidc.token(username=self.username, password=self.password) else: token = self.oidc.token(username=self.username) self.token_util.process_token(token) return self.token_util.token def refresh_token(self): """ Obtains a new access token if the access token is expired. if refresh token is expired, this method prompt user to re-authenticate when `delegate_login` is `False` or raise an `presalytics.lib.exceptions.InvalidTokenException` when `deletegate_login` is True. """ if self.token_util.is_api_access_token_expired(): if self.token_util.token.get('refresh_token', None) and self.client_secret: refresh_token = self.token_util.token["refresh_token"] token = self.oidc.refresh_token(refresh_token) self.token_util.process_token(token) logger.debug("Refresh token granted successfully.") else: if self.direct_grant: token = self.oidc.token(username=self.username, password=self.password) elif self.confidential_client: token = self.oidc.client_credentials_token() elif self._delegate_login: raise presalytics.lib.exceptions.ApiError("Unauthorized. Token has expired", status_code=401) else: token = self.oidc.token(username=self.username) self.token_util.process_token(token) if self.token_util.token_cache: self.token_util._put_token_file() return self.token_util.token def get_auth_header(self): """ Creates a JWT Bearer Authorization token header Returns ---------- A `dict` authorization crediential to be attached to an API request """ self.refresh_token() auth_header = { "Authorization": "Bearer " + self.token_util.token["access_token"] } return auth_header def get_request_id_header(self): """ Creates an 'X-Request-Id' token header for tracing requests through Presalytics API services. If deployed alongside the [WSGI Microservice Middleware](https://github.com/presalytics/WSGI-Microservice-Middleware) package, this method will pull the request id from the call stack. Returns ---------- A `dict` header representation with an 'X-Request-Id' key to be attached to an API request """ current_request_id = wsgi_microservice_middleware.current_request_id() if not current_request_id: current_request_id = str(uuid4()) header = { "X-Request-Id": current_request_id } return header def download_file(self, story_id, ooxml_automation_id, download_folder=None, filename=None, **kwargs): """ Downloads an updated Ooxml Automation file and places the file in a designated folder Parameters --------- story : str The id of the Presalytics Story API object that manages access to document ooxml_automation_id : str The id of the Presalytics API Ooxml Automation service object that you want to download download_folder : str, optional The filepath to the local directory that you want to download the file to. Defaults to the current working directory. filename: str, optional The name of the downloaded file. Defaults to the original filename the the object was created. """ response, status, headers = self.story.story_id_file_ooxmlautomationid_get_with_http_info(story_id, ooxml_automation_id, _preload_content=False) if download_folder is None: download_folder = os.getcwd() if filename is None: cd_header = headers.get('Content-Disposition') _, params = cgi.parse_header(cd_header) filename = params["filename"] filepath = os.path.join(download_folder, filename) with open(filepath, 'wb') as f: f.write(response.data) def get_client_info(self): """ Convenience method returning information about this client to pass to downstream objects, e.g., components and new client instances Returns ---------- A dictionary containing instances values: - token: self.token_util.token - client_id: self.client_id - cache_tokens: self.token_util.token_cache - delegate_login: self.delegate login """ return { "token": self.token_util.token, "client_id": self.client_id, "cache_tokens": self.token_util.token_cache, "delegate_login": self._delegate_login } STATUS_REPOLL_SECONDS = 2 STATUS_REPOLL_MAX_CYCLES = 20 def upload_file_and_await_outline(self, file: typing.Union[FileStorage, str], include_relationships=True, status_repoll_seconds: int = None, repoll_max_cycles: int = None): """ Useful for testing """ if type(file) is str: content_type = mimetypes.guess_type(file, False)[0] # type: ignore with open(file, 'rb') as f: # type: ignore stream = io.BytesIO(f.read()) file = FileStorage( stream=stream, # type: ignore filename=file, # type: ignore content_type=content_type, content_length=stream.__sizeof__() ) if not status_repoll_seconds: status_repoll_seconds = self.STATUS_REPOLL_SECONDS if not repoll_max_cycles: repoll_max_cycles = self.STATUS_REPOLL_MAX_CYCLES story = self.story.story_post_file(file=file) self.await_outline(story.id) return self.story.story_id_get(story.id, include_outline=True, include_relationships=include_relationships) def await_outline(self, story_id, status_repoll_seconds: int = None, repoll_max_cycles: int = None): task_running = True repoll_cycle_count = 0 if not status_repoll_seconds: status_repoll_seconds = self.STATUS_REPOLL_SECONDS if not repoll_max_cycles: repoll_max_cycles = self.STATUS_REPOLL_MAX_CYCLES while task_running: status, status_code, _ = self.story.story_id_status_get_with_http_info(story_id) if status_code == 204: task_running = False elif status_code == 200: if status.status == "SUCCESS": task_running = False elif repoll_cycle_count >= repoll_max_cycles: raise presalytics.lib.exceptions.ApiError(message="Error occured while uploading file", status_code=500) else: logger.info("Story creation task still running. Rechecking status in {0} seconds".format(status_repoll_seconds)) time.sleep(status_repoll_seconds) repoll_cycle_count += 1 return self.story.story_id_outline_get(story_id)
Class variables
var STATUS_REPOLL_SECONDS
-
int(x=0) -> integer int(x, base=10) -> integer
Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.int(). For floating point numbers, this truncates towards zero.
If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0) 4
var STATUS_REPOLL_MAX_CYCLES
-
int(x=0) -> integer int(x, base=10) -> integer
Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.int(). For floating point numbers, this truncates towards zero.
If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0) 4
Methods
def login(self)
-
Triggers a an attempt to acquire an API token based on the the client configuration
Expand source code Browse git
def login(self): """ Triggers a an attempt to acquire an API token based on the the client configuration """ if self.direct_grant: token = self.oidc.token(username=self.username, password=self.password) else: token = self.oidc.token(username=self.username) self.token_util.process_token(token) return self.token_util.token
def refresh_token(self)
-
Obtains a new access token if the access token is expired. if refresh token is expired, this method prompt user to re-authenticate when
delegate_login
isFalse
or raise anInvalidTokenException
whendeletegate_login
is True.Expand source code Browse git
def refresh_token(self): """ Obtains a new access token if the access token is expired. if refresh token is expired, this method prompt user to re-authenticate when `delegate_login` is `False` or raise an `presalytics.lib.exceptions.InvalidTokenException` when `deletegate_login` is True. """ if self.token_util.is_api_access_token_expired(): if self.token_util.token.get('refresh_token', None) and self.client_secret: refresh_token = self.token_util.token["refresh_token"] token = self.oidc.refresh_token(refresh_token) self.token_util.process_token(token) logger.debug("Refresh token granted successfully.") else: if self.direct_grant: token = self.oidc.token(username=self.username, password=self.password) elif self.confidential_client: token = self.oidc.client_credentials_token() elif self._delegate_login: raise presalytics.lib.exceptions.ApiError("Unauthorized. Token has expired", status_code=401) else: token = self.oidc.token(username=self.username) self.token_util.process_token(token) if self.token_util.token_cache: self.token_util._put_token_file() return self.token_util.token
def get_auth_header(self)
-
Creates a JWT Bearer Authorization token header
Returns
A
dict
authorization crediential to be attached to an API requestExpand source code Browse git
def get_auth_header(self): """ Creates a JWT Bearer Authorization token header Returns ---------- A `dict` authorization crediential to be attached to an API request """ self.refresh_token() auth_header = { "Authorization": "Bearer " + self.token_util.token["access_token"] } return auth_header
def get_request_id_header(self)
-
Creates an 'X-Request-Id' token header for tracing requests through Presalytics API services. If deployed alongside the WSGI Microservice Middleware package, this method will pull the request id from the call stack.
Returns
A
dict
header representation with an 'X-Request-Id' key to be attached to an API requestExpand source code Browse git
def get_request_id_header(self): """ Creates an 'X-Request-Id' token header for tracing requests through Presalytics API services. If deployed alongside the [WSGI Microservice Middleware](https://github.com/presalytics/WSGI-Microservice-Middleware) package, this method will pull the request id from the call stack. Returns ---------- A `dict` header representation with an 'X-Request-Id' key to be attached to an API request """ current_request_id = wsgi_microservice_middleware.current_request_id() if not current_request_id: current_request_id = str(uuid4()) header = { "X-Request-Id": current_request_id } return header
def download_file(self, story_id, ooxml_automation_id, download_folder=None, filename=None, **kwargs)
-
Downloads an updated Ooxml Automation file and places the file in a designated folder
Parameters
story
:str
- The id of the Presalytics Story API object that manages access to document
ooxml_automation_id
:str
- The id of the Presalytics API Ooxml Automation service object that you want to download
download_folder
:str
, optional- The filepath to the local directory that you want to download the file to. Defaults to the current working directory.
filename
:str
, optional- The name of the downloaded file. Defaults to the original filename the the object was created.
Expand source code Browse git
def download_file(self, story_id, ooxml_automation_id, download_folder=None, filename=None, **kwargs): """ Downloads an updated Ooxml Automation file and places the file in a designated folder Parameters --------- story : str The id of the Presalytics Story API object that manages access to document ooxml_automation_id : str The id of the Presalytics API Ooxml Automation service object that you want to download download_folder : str, optional The filepath to the local directory that you want to download the file to. Defaults to the current working directory. filename: str, optional The name of the downloaded file. Defaults to the original filename the the object was created. """ response, status, headers = self.story.story_id_file_ooxmlautomationid_get_with_http_info(story_id, ooxml_automation_id, _preload_content=False) if download_folder is None: download_folder = os.getcwd() if filename is None: cd_header = headers.get('Content-Disposition') _, params = cgi.parse_header(cd_header) filename = params["filename"] filepath = os.path.join(download_folder, filename) with open(filepath, 'wb') as f: f.write(response.data)
def get_client_info(self)
-
Convenience method returning information about this client to pass to downstream objects, e.g., components and new client instances
Returns
A
dictionary
containing
instances
values
:-
- token: self.token_util.token
- client_id: self.client_id
- cache_tokens: self.token_util.token_cache
- delegate_login: self.delegate login
Expand source code Browse git
def get_client_info(self): """ Convenience method returning information about this client to pass to downstream objects, e.g., components and new client instances Returns ---------- A dictionary containing instances values: - token: self.token_util.token - client_id: self.client_id - cache_tokens: self.token_util.token_cache - delegate_login: self.delegate login """ return { "token": self.token_util.token, "client_id": self.client_id, "cache_tokens": self.token_util.token_cache, "delegate_login": self._delegate_login }
def upload_file_and_await_outline(self, file, include_relationships=True, status_repoll_seconds=None, repoll_max_cycles=None)
-
Useful for testing
Expand source code Browse git
def upload_file_and_await_outline(self, file: typing.Union[FileStorage, str], include_relationships=True, status_repoll_seconds: int = None, repoll_max_cycles: int = None): """ Useful for testing """ if type(file) is str: content_type = mimetypes.guess_type(file, False)[0] # type: ignore with open(file, 'rb') as f: # type: ignore stream = io.BytesIO(f.read()) file = FileStorage( stream=stream, # type: ignore filename=file, # type: ignore content_type=content_type, content_length=stream.__sizeof__() ) if not status_repoll_seconds: status_repoll_seconds = self.STATUS_REPOLL_SECONDS if not repoll_max_cycles: repoll_max_cycles = self.STATUS_REPOLL_MAX_CYCLES story = self.story.story_post_file(file=file) self.await_outline(story.id) return self.story.story_id_get(story.id, include_outline=True, include_relationships=include_relationships)
def await_outline(self, story_id, status_repoll_seconds=None, repoll_max_cycles=None)
-
Expand source code Browse git
def await_outline(self, story_id, status_repoll_seconds: int = None, repoll_max_cycles: int = None): task_running = True repoll_cycle_count = 0 if not status_repoll_seconds: status_repoll_seconds = self.STATUS_REPOLL_SECONDS if not repoll_max_cycles: repoll_max_cycles = self.STATUS_REPOLL_MAX_CYCLES while task_running: status, status_code, _ = self.story.story_id_status_get_with_http_info(story_id) if status_code == 204: task_running = False elif status_code == 200: if status.status == "SUCCESS": task_running = False elif repoll_cycle_count >= repoll_max_cycles: raise presalytics.lib.exceptions.ApiError(message="Error occured while uploading file", status_code=500) else: logger.info("Story creation task still running. Rechecking status in {0} seconds".format(status_repoll_seconds)) time.sleep(status_repoll_seconds) repoll_cycle_count += 1 return self.story.story_id_outline_get(story_id)
class DocConverterApiClientWithAuth (parent, **kwargs)
-
Wraps
ApiClient
withAuthenticationMixIn
middlewareExpand source code Browse git
class DocConverterApiClientWithAuth(presalytics.client.auth.AuthenticationMixIn, presalytics.client.presalytics_doc_converter.api_client.ApiClient): """ Wraps `presalytics.client.presalytics_doc_converter.api_client.ApiClient` with `presalytics.client.auth.AuthenticationMixIn` middleware """ def __init__(self, parent: Client, **kwargs): presalytics.client.auth.AuthenticationMixIn.__init__(self, parent, **kwargs) presalytics.client.presalytics_doc_converter.api_client.ApiClient.__init__(self) self.update_configuration() @property def api_name(self): return 'doc-converter'
Ancestors
- AuthenticationMixIn
- abc.ABC
- ApiClient
Instance variables
var api_name
-
Expand source code Browse git
@property def api_name(self): return 'doc-converter'
Inherited members
class OoxmlAutomationApiClientWithAuth (parent, **kwargs)
-
Wraps
ApiClient
withAuthenticationMixIn
middlewareExpand source code Browse git
class OoxmlAutomationApiClientWithAuth(presalytics.client.auth.AuthenticationMixIn, presalytics.client.presalytics_ooxml_automation.api_client.ApiClient): """ Wraps `presalytics.client.presalytics_ooxml_automation.api_client.ApiClient` with `presalytics.client.auth.AuthenticationMixIn` middleware """ def __init__(self, parent: Client, **kwargs): presalytics.client.auth.AuthenticationMixIn.__init__(self, parent, **kwargs) presalytics.client.presalytics_ooxml_automation.api_client.ApiClient.__init__(self) self.update_configuration() @property def api_name(self): return 'ooxml-automation'
Ancestors
- AuthenticationMixIn
- abc.ABC
- ApiClient
Instance variables
var api_name
-
Expand source code Browse git
@property def api_name(self): return 'ooxml-automation'
Inherited members
class StoryApiClientWithAuth (parent, **kwargs)
-
Wraps
ApiClient
withAuthenticationMixIn
middlewareExpand source code Browse git
class StoryApiClientWithAuth(presalytics.client.auth.AuthenticationMixIn, presalytics.client.presalytics_story.api_client.ApiClient): """ Wraps `presalytics.client.presalytics_story.api_client.ApiClient` with `presalytics.client.auth.AuthenticationMixIn` middleware """ def __init__(self, parent: Client, **kwargs): presalytics.client.auth.AuthenticationMixIn.__init__(self, parent, **kwargs) presalytics.client.presalytics_story.api_client.ApiClient.__init__(self) self.update_configuration() @property def api_name(self): return 'story'
Ancestors
- AuthenticationMixIn
- abc.ABC
- ApiClient
Instance variables
var api_name
-
Expand source code Browse git
@property def api_name(self): return 'story'
Inherited members