Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions tabcmd/commands/auth/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,15 @@ def _read_existing_state(self):
self._read_from_json()

def _print_server_info(self):
self.logger.info("===== Server: {}".format(self.server_url))
self.logger.info(" Server: {}".format(self.server_url))
if self.proxy:
self.logger.info("===== Proxy: {}".format(self.proxy))
self.logger.info(" Proxy: {}".format(self.proxy))
if self.username:
self.logger.info("===== Username: {}".format(self.username))
self.logger.info(" Username: {}".format(self.username))
if self.certificate:
self.logger.info("===== Certificate: {}".format(self.certificate))
self.logger.info(" Certificate: {}".format(self.certificate))
else:
self.logger.info("===== Token Name: {}".format(self.token_name))
self.logger.info(" Token Name: {}".format(self.token_name))
site_display_name = self.site_name or "Default Site"
self.logger.info(_("dataconnections.classes.tableau_server_site") + ": {}".format(site_display_name))

Expand All @@ -281,7 +281,7 @@ def _validate_existing_signin(self):
if self.tableau_server and self.tableau_server.is_signed_in() and self.user_id:
server_user = self.tableau_server.users.get_by_id(self.user_id).name
if not self.username:
self.logger.info("Fetched user details from server")
self.logger.debug("Fetched user details from server")
self.username = server_user

return self.tableau_server
Expand All @@ -296,6 +296,7 @@ def _sign_in(self, tableau_auth) -> TSC.Server:
if not self.tableau_server:
Errors.exit_with_error(self.logger, "No server connection available for sign in")

self.logger.info(_("session.login"))
self.logger.debug(_("session.login") + (self.server_url or ""))
self.logger.debug(_("listsites.output").format("", self.username or self.token_name, self.site_name))
assert self.tableau_server is not None # Type hint for mypy
Expand Down
6 changes: 3 additions & 3 deletions tabcmd/commands/constants.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import inspect
import requests
import sys
from typing import Optional
from typing import NoReturn, Optional

import tableauserverclient

Expand Down Expand Up @@ -58,14 +58,14 @@ def log_stack(logger):
logger.info("Error printing stack trace:", e)

@staticmethod
def exit_with_error(logger, message: Optional[str] = None, exception: Optional[Exception] = None):
def exit_with_error(logger, message: Optional[str] = None, exception: Optional[Exception] = None) -> NoReturn:
try:
if message and not exception:
logger.error(message)
Errors.log_stack(logger)
elif exception:
if message:
logger.info(_("tabcmd.debug.error_message") + message)
logger.debug(_("tabcmd.debug.error_message") + message)
Errors.check_common_error_codes_and_explain(logger, exception)
else:
logger.info(_("tabcmd.debug.no_exception_or_message"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,22 @@ def apply_csv_options(logger, request_options: TSC.CSVRequestOptions, args):
request_options.language = args.language

@staticmethod
def save_to_data_file(logger, output, filename):
def save_to_data_file(logger, output, filename, content_name=None):
logger.info(_("httputils.found_attachment").format(filename))
with open(filename, "wb") as f:
f.writelines(output)
logger.info(_("export.success").format("", filename))
# export.success renders as 'Saved <content> to "<filename>"' -- content
# name is the workbook/view/datasource being exported, filename is the
# destination path. Fall back to filename twice if no content name was
# threaded through (better than an empty {0}).
logger.info(_("export.success").format(content_name or filename, filename))

@staticmethod
def save_to_file(logger, output, filename):
def save_to_file(logger, output, filename, content_name=None):
logger.info(_("httputils.found_attachment").format(filename))
with open(filename, "wb") as f:
f.write(output)
logger.info(_("export.success").format("", filename))
logger.info(_("export.success").format(content_name or filename, filename))

@staticmethod
def get_custom_view_by_id(logger, server, custom_view_id) -> TSC.CustomViewItem:
Expand Down
4 changes: 3 additions & 1 deletion tabcmd/commands/datasources_and_workbooks/delete_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ def run_command(cls, args):
else:

Errors.exit_with_error(logger, _("tabcmd.errors.parent.not.found"))
logger.info(_("delete.status").format(content_type, item_name or args.name))

item_to_delete = None
error = None
if args.workbook or not content_type:
logger.debug(_("delete.status").format("Workbook", args.workbook))
Expand All @@ -68,6 +68,8 @@ def run_command(cls, args):
logger.debug(error)
Errors.exit_with_error(logger, _("delete.errors.requires_workbook_datasource"))

logger.info(_("delete.status").format(content_type, args.name))

try:
if content_type == "workbook":
server.workbooks.delete(item_to_delete.id)
Expand Down
28 changes: 16 additions & 12 deletions tabcmd/commands/datasources_and_workbooks/export_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,41 +102,45 @@ def run_command(cls, args):
)
Errors.exit_with_error(logger, message)

# `content_item` tracks the workbook/view/custom_view we're exporting; used
# for the "Saved <content-name> to '<filename>'" success message.
content_item = None
try:
if args.fullpdf: # it's a workbook
workbook_item = ExportCommand.get_wb_by_content_url(logger, server, wb_content_url)
output = ExportCommand.download_wb_pdf(server, workbook_item, args, logger)
content_item = ExportCommand.get_wb_by_content_url(logger, server, wb_content_url)
output = ExportCommand.download_wb_pdf(server, content_item, args, logger)

default_filename = "{}.pdf".format(workbook_item.name)
default_filename = "{}.pdf".format(content_item.name)

elif args.pdf or args.png or args.csv: # it's a view or custom_view
(
export_item,
content_item,
server_content_type,
) = DatasourcesWorkbooksAndViewsUrlParser.get_export_item_and_server_content_type_from_export_url(
view_content_url, logger, server, custom_view_id
)

if args.pdf:
output = ExportCommand.download_view_pdf(server_content_type, export_item, args, logger)
default_filename = "{}.pdf".format(export_item.name)
output = ExportCommand.download_view_pdf(server_content_type, content_item, args, logger)
default_filename = "{}.pdf".format(content_item.name)
elif args.csv:
output = ExportCommand.download_csv(server_content_type, export_item, args, logger)
default_filename = "{}.csv".format(export_item.name)
output = ExportCommand.download_csv(server_content_type, content_item, args, logger)
default_filename = "{}.csv".format(content_item.name)
elif args.png:
output = ExportCommand.download_png(server_content_type, export_item, args, logger)
default_filename = "{}.png".format(export_item.name)
output = ExportCommand.download_png(server_content_type, content_item, args, logger)
default_filename = "{}.png".format(content_item.name)

except TSC.ServerResponseError as e:
Errors.exit_with_error(logger, _("publish.errors.unexpected_server_response").format(""), exception=e)
except Exception as e:
Errors.exit_with_error(logger, exception=e)
try:
save_name = args.filename or default_filename
content_name = content_item.name if content_item is not None else None
if args.csv:
ExportCommand.save_to_data_file(logger, output, save_name)
ExportCommand.save_to_data_file(logger, output, save_name, content_name=content_name)
else:
ExportCommand.save_to_file(logger, output, save_name)
ExportCommand.save_to_file(logger, output, save_name, content_name=content_name)

except Exception as e:
Errors.exit_with_error(logger, "Error saving to file", exception=e)
Expand Down
8 changes: 5 additions & 3 deletions tabcmd/commands/datasources_and_workbooks/get_url_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def generate_pdf(logger, server_content_type, args, get_url_item):
DatasourcesAndWorkbooks.apply_values_from_url_params(logger, req_option_pdf, args.url)
server_content_type.populate_pdf(get_url_item, req_option_pdf)
filename = GetUrl.filename_from_args(args.filename, get_url_item.name, "pdf")
DatasourcesAndWorkbooks.save_to_file(logger, get_url_item.pdf, filename)
DatasourcesAndWorkbooks.save_to_file(logger, get_url_item.pdf, filename, content_name=get_url_item.name)
except Exception as e:
Errors.exit_with_error(logger, exception=e)

Expand All @@ -119,7 +119,7 @@ def generate_png(logger, server_content_type, args, get_url_item):
DatasourcesAndWorkbooks.apply_values_from_url_params(logger, req_option_png, args.url)
server_content_type.populate_image(get_url_item, req_option_png)
filename = GetUrl.filename_from_args(args.filename, get_url_item.name, "png")
DatasourcesAndWorkbooks.save_to_file(logger, get_url_item.image, filename)
DatasourcesAndWorkbooks.save_to_file(logger, get_url_item.image, filename, content_name=get_url_item.name)
except Exception as e:
Errors.exit_with_error(logger, exception=e)

Expand All @@ -132,7 +132,9 @@ def generate_csv(logger, server_content_type, args, get_url_item):
DatasourcesAndWorkbooks.apply_values_from_url_params(logger, req_option_csv, args.url)
server_content_type.populate_csv(get_url_item, req_option_csv)
file_name_with_path = GetUrl.filename_from_args(args.filename, get_url_item.name, "csv")
DatasourcesAndWorkbooks.save_to_data_file(logger, get_url_item.csv, file_name_with_path)
DatasourcesAndWorkbooks.save_to_data_file(
logger, get_url_item.csv, file_name_with_path, content_name=get_url_item.name
)
except Exception as e:
Errors.exit_with_error(logger, exception=e)

Expand Down
2 changes: 1 addition & 1 deletion tabcmd/commands/group/delete_group_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def run_command(cls, args):
try:
logger.info(_("tabcmd.find.group").format(args.name))
group_id = Server.find_group(logger, server, args.name).id
logger.info(_("deletegroup.status").format(group_id))
logger.info(_("deletegroup.status").format(args.name))
server.groups.delete(group_id)
logger.info(_("common.output.succeeded"))
except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion tabcmd/commands/site/list_sites_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def run_command(cls, args):
sites, pagination = server.sites.get()
logger.info(_("listsites.status").format(session.username))
for site in sites:
logger.info(_("listsites.output").format(" ", site.name, site.id))
logger.info(_("listsites.output").format(" ", site.name, site.content_url))
if args.get_extract_encryption_mode:
logger.info("EXTRACTENCRYPTION: {}".format(site.extract_encryption_mode))
except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion tabcmd/commands/user/create_site_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def run_command(cls, args):
logger.debug(type(e))
number_of_errors += 1
logger.debug(number_of_errors)
error_list.append(e.__class__.__name__) # + ": " + e.__cause__ or "Unknown")
error_list.append(str(e))
logger.debug(error_list)
logger.info(_("session.monitorjob.percent_complete").format(100))
logger.info(_("importcsvsummary.line.processed").format(number_of_users_listed))
Expand Down
2 changes: 1 addition & 1 deletion tabcmd/commands/user/remove_users_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ def run_command(cls, args):
session = Session()
server = session.create_session(args, logger)

logger.info(_("tabcmd.removeusers.server").format(args.users.name, args.name))
logger.info(_("tabcmd.removeusers.group").format(args.users.name, args.name))

UserCommand.act_on_users(logger, server, "removed", server.groups.remove_user, args)
8 changes: 7 additions & 1 deletion tabcmd/execution/logger_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@

path = os.path.dirname(os.path.abspath(__file__))

# tabcmd Classic prefixes every INFO line with "=====". This PR's goal is parity
# with Classic output, so the prefix is on by default. Users who prefer the
# plainer tabcmd 2 style can opt out with TABCMD_CLASSIC_OUTPUT=false (or 0/no).
_CLASSIC_OUTPUT = os.environ.get("TABCMD_CLASSIC_OUTPUT", "true").lower() not in ("0", "false", "no")
_INFO_FORMAT = "===== %(message)-30s" if _CLASSIC_OUTPUT else "%(message)-30s"

FORMATS = {
logging.ERROR: "%(asctime)s %(levelname)-5s:(%(name)-10s %(filename)-10s: %(lineno)d): %(message)-30s",
logging.WARN: "%(asctime)s %(levelname)-5s: (%(name)-10s %(filename)-10s: %(lineno)d): %(message)-30s",
logging.INFO: "%(message)-30s",
logging.INFO: _INFO_FORMAT,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacalata please check this, I'm not sure the right answer

logging.DEBUG: "%(asctime)s %(levelname)-5s: (%(name)-10s %(filename)-10s: %(lineno)d): %(message)-30s",
}

Expand Down
4 changes: 2 additions & 2 deletions tabcmd/execution/parent_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,5 +198,5 @@ def __init__(self, _parser: ParentParser):

def run_command(self, args):
logger = log(__name__, "info")
logger.info(f"{_('tabcmd.name')} {version}\n")
logger.info(self.parser.root.format_help())
print(f"{_('tabcmd.name')} {version}\n")
print(self.parser.root.format_help())
7 changes: 2 additions & 5 deletions tabcmd/execution/tabcmd_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ def run(parser, user_input=None):
parser.print_help()
sys.exit(0)

if hasattr(namespace, "logging_level") and namespace.logging_level != logging.INFO:
print("logging:", namespace.logging_level)

logger = log(__name__, namespace.logging_level or logging.INFO)
logger.info("Tabcmd {}".format(version))
logger = log(__name__, namespace.logging_level or "INFO")
print("Tabcmd {}".format(version))
if hasattr(namespace, "password") or hasattr(namespace, "token_value"):
# don't print whole namespace because it has secrets
logger.debug(namespace.func)
Expand Down
Binary file modified tabcmd/locales/de/LC_MESSAGES/tabcmd.mo
Binary file not shown.
1 change: 1 addition & 0 deletions tabcmd/locales/de/tabcmd_messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ tabcmd.publish.options.append.detailed=Fügen Sie die zu veröffentlichenden Dat
tabcmd.publish.options.tabbed.detailed=Veröffentlichen Sie mit aktivierter Einstellung „Ansichten mit Registerkarten“. Jedes Blatt wird als separate Registerkarte angezeigt, die Benutzer verwenden können, um in der Arbeitsmappe zu navigieren.
tabcmd.refresh.options.bridge=Datenquelle über Tableau Bridge aktualisieren
tabcmd.removeusers.server=Removing users listed in {0} from the server...
tabcmd.removeusers.group=Removing users listed in {0} from the group ''{1}''...
tabcmd.report.error.user_csv.at_char=If a user name includes an @ character that represents anything other than a domain separator, you need to refer to the symbol using the hexadecimal format: \\0x40
tabcmd.report.error.user_csv.too_many_columns=The file contains {0} columns, but there are only {1} valid columns in a user import csv file
tabcmd.report.error.user.no_spaces_in_username=Username cannot contain spaces
Expand Down
Binary file modified tabcmd/locales/en/LC_MESSAGES/tabcmd.mo
Binary file not shown.
3 changes: 2 additions & 1 deletion tabcmd/locales/en/tabcmd_messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ tabcmd.global.help.page_size=Specify the page size for query results
tabcmd.global.help.skip_connection_check=Skip connection check: do not validate the connection during publishing
tabcmd.howto=Run a specific command
tabcmd.launching=Launching tabcmd
tabcmd.listing.header====== Listing {0} content for user {1}...
tabcmd.listing.header=Listing {0} content for user {1}...
tabcmd.listing.label.id=ID: {}
tabcmd.listing.label.name=\tNAME: {}
tabcmd.listing.none=No content found
Expand Down Expand Up @@ -205,6 +205,7 @@ tabcmd.publish.options.tabbed.detailed=Publish with tabbed views enabled. Each s
tabcmd.refresh.options.bridge=Refresh datasource through Tableau Bridge
tabcmd.removeusers.help.group_name=The group to remove users from
tabcmd.removeusers.server=Removing users listed in {0} from the server...
tabcmd.removeusers.group=Removing users listed in {0} from the group ''{1}''...
tabcmd.report.error.user_csv.at_char=If a user name includes an @ character that represents anything other than a domain separator, you need to refer to the symbol using the hexadecimal format: \\0x40
tabcmd.report.error.user_csv.too_many_columns=The file contains {0} columns, but there are only {1} valid columns in a user import csv file
tabcmd.report.error.user.no_spaces_in_username=Username cannot contain spaces
Expand Down
Binary file modified tabcmd/locales/es/LC_MESSAGES/tabcmd.mo
Binary file not shown.
1 change: 1 addition & 0 deletions tabcmd/locales/es/tabcmd_messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ tabcmd.publish.options.append.detailed=Anexar los datos que se van a publicar a
tabcmd.publish.options.tabbed.detailed=Publicar con vistas tabuladas habilitadas. Cada hoja se convierte en una pestaña que los viewers pueden usar para navegar por el libro de trabajo.
tabcmd.refresh.options.bridge=Actualizar fuente de datos a través de Tableau Bridge
tabcmd.removeusers.server=Removing users listed in {0} from the server...
tabcmd.removeusers.group=Removing users listed in {0} from the group ''{1}''...
tabcmd.report.error.user_csv.at_char=If a user name includes an @ character that represents anything other than a domain separator, you need to refer to the symbol using the hexadecimal format: \\0x40
tabcmd.report.error.user_csv.too_many_columns=The file contains {0} columns, but there are only {1} valid columns in a user import csv file
tabcmd.report.error.user.no_spaces_in_username=Username cannot contain spaces
Expand Down
Binary file modified tabcmd/locales/fr/LC_MESSAGES/tabcmd.mo
Binary file not shown.
1 change: 1 addition & 0 deletions tabcmd/locales/fr/tabcmd_messages_fr.properties
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ tabcmd.publish.options.append.detailed=Ajoutez les données à publier à une so
tabcmd.publish.options.tabbed.detailed=Publier en activant les vues avec onglets. Chaque feuille devient un onglet que les Viewers peuvent utiliser pour parcourir le classeur.
tabcmd.refresh.options.bridge=Actualiser une source de données via Tableau Bridge
tabcmd.removeusers.server=Removing users listed in {0} from the server...
tabcmd.removeusers.group=Removing users listed in {0} from the group ''{1}''...
tabcmd.report.error.user_csv.at_char=If a user name includes an @ character that represents anything other than a domain separator, you need to refer to the symbol using the hexadecimal format: \\0x40
tabcmd.report.error.user_csv.too_many_columns=The file contains {0} columns, but there are only {1} valid columns in a user import csv file
tabcmd.report.error.user.no_spaces_in_username=Username cannot contain spaces
Expand Down
Binary file modified tabcmd/locales/ga/LC_MESSAGES/tabcmd.mo
Binary file not shown.
1 change: 1 addition & 0 deletions tabcmd/locales/ga/tabcmd_messages_ga.properties
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ tabcmd.publish.options.append.detailed=a46d-表:Append the data being published
tabcmd.publish.options.tabbed.detailed=1e5f-表:Publish with tabbed views enabled. Each sheet becomes a tab that viewers can use to navigate through the workbook.|桜
tabcmd.refresh.options.bridge=22fe-表:Refresh datasource through Tableau Bridge|桜
tabcmd.removeusers.server=Removing users listed in {0} from the server...
tabcmd.removeusers.group=Removing users listed in {0} from the group ''{1}''...
tabcmd.report.error.user_csv.at_char=If a user name includes an @ character that represents anything other than a domain separator, you need to refer to the symbol using the hexadecimal format: \\0x40
tabcmd.report.error.user_csv.too_many_columns=The file contains {0} columns, but there are only {1} valid columns in a user import csv file
tabcmd.report.error.user.no_spaces_in_username=Username cannot contain spaces
Expand Down
Binary file modified tabcmd/locales/it/LC_MESSAGES/tabcmd.mo
Binary file not shown.
Loading
Loading