diff --git a/tableauserverclient/config.py b/tableauserverclient/config.py index a75112754..a0b618578 100644 --- a/tableauserverclient/config.py +++ b/tableauserverclient/config.py @@ -8,19 +8,24 @@ class Config: + """Runtime configuration for TSC, controllable via environment variables.""" + # The maximum size of a file that can be published in a single request is 64MB @property def FILESIZE_LIMIT_MB(self): + """Maximum single-request publish size in MB (env: TSC_FILESIZE_LIMIT_MB, capped at 64).""" return min(int(os.getenv("TSC_FILESIZE_LIMIT_MB", 64)), 64) # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks @property def CHUNK_SIZE_MB(self): + """Chunk size in MB for multipart publish requests (env: TSC_CHUNK_SIZE_MB).""" return int(os.getenv("TSC_CHUNK_SIZE_MB", 5 * 10)) # 5MB felt too slow, upped it to 50 # Default page size @property def PAGE_SIZE(self): + """Default page size for paginated API requests (env: TSC_PAGE_SIZE).""" return int(os.getenv("TSC_PAGE_SIZE", 100)) diff --git a/tableauserverclient/datetime_helpers.py b/tableauserverclient/datetime_helpers.py index 7beb0276e..ce5d60697 100644 --- a/tableauserverclient/datetime_helpers.py +++ b/tableauserverclient/datetime_helpers.py @@ -5,13 +5,14 @@ def timestamp(): + """Return the current local time as an HH:MM:SS string.""" return datetime.datetime.now().strftime("%H:%M:%S") # This class is a concrete implementation of the abstract base class tzinfo # docs: https://docs.python.org/2.3/lib/datetime-tzinfo.html class UTC(datetime.tzinfo): - """UTC""" + """UTC timezone implementation for use with datetime objects.""" def utcoffset(self, dt): return ZERO @@ -28,6 +29,7 @@ def dst(self, dt): def parse_datetime(date): + """Parse a Tableau API datetime string into a UTC-aware datetime, or None if absent or unparseable.""" if date is None: return None @@ -38,6 +40,7 @@ def parse_datetime(date): def format_datetime(date): + """Format a datetime as a Tableau API datetime string, or None if absent.""" if date is None: return None diff --git a/tableauserverclient/exponential_backoff.py b/tableauserverclient/exponential_backoff.py index 69ffdc96b..8e735d73a 100644 --- a/tableauserverclient/exponential_backoff.py +++ b/tableauserverclient/exponential_backoff.py @@ -7,12 +7,15 @@ class ExponentialBackoffTimer: + """Timer for polling server-side events with exponential backoff between attempts.""" + def __init__(self, *, timeout=None): self.start_time = time.time() self.timeout = timeout self.current_sleep_interval = ASYNC_POLL_MIN_INTERVAL def sleep(self): + """Sleep for the next backoff interval, raising TimeoutError if the timeout deadline has passed.""" max_sleep_time = ASYNC_POLL_MAX_INTERVAL if self.timeout is not None: elapsed = time.time() - self.start_time diff --git a/tableauserverclient/filesys_helpers.py b/tableauserverclient/filesys_helpers.py index 1663ee9e8..11d41d934 100644 --- a/tableauserverclient/filesys_helpers.py +++ b/tableauserverclient/filesys_helpers.py @@ -4,11 +4,13 @@ def to_filename(string_to_sanitize): + """Strip characters from a string that are not safe for use in a filename.""" sanitized = (c for c in string_to_sanitize if c.isalnum() or c in ALLOWED_SPECIAL) return "".join(sanitized) def make_download_path(filepath, filename): + """Resolve a download destination path from an optional target filepath and the server-provided filename.""" download_path = None if filepath is None: @@ -24,6 +26,7 @@ def make_download_path(filepath, filename): def get_file_object_size(file): + """Return the size in bytes of an open binary file object.""" # Returns the size of a file object file.seek(0, os.SEEK_END) file_size = file.tell() @@ -32,6 +35,7 @@ def get_file_object_size(file): def get_file_type(file): + """Detect the type of an open binary file by inspecting its magic bytes, returning one of 'zip', 'tde', 'xml', or 'hyper'.""" # Tableau workbooks (twb) and data sources (tds) are both stored as xml files. # Packaged workbooks (twbx) and data sources (tdsx) are zip files # containing original files accompanied with supporting local files. diff --git a/tableauserverclient/namespace.py b/tableauserverclient/namespace.py index 54ac46d8d..00d6f65b9 100644 --- a/tableauserverclient/namespace.py +++ b/tableauserverclient/namespace.py @@ -8,10 +8,12 @@ class UnknownNamespaceError(Exception): - pass + """Raised when an XML response contains an unrecognized Tableau API namespace.""" class Namespace: + """Detects and stores the Tableau REST API XML namespace from server responses.""" + def __init__(self): self._namespace = {"t": NEW_NAMESPACE} self._detected = False @@ -20,6 +22,7 @@ def __call__(self): return self._namespace def detect(self, xml): + """Detect the XML namespace from raw response bytes, updating the stored namespace on first call.""" if self._detected: return