def wrapper(*args, **kwargs): try: return function(*args, **kwargs) except ValidationError as error: sys.exit(error.exit_code) except SpectaclesException as error: logger.error( f"{error}\n\n" + printer.dim( "For support, please create an issue at " "https://github.com/spectacles-ci/spectacles/issues" ) + "\n" ) sys.exit(error.exit_code) except Exception as error: logger.debug(error, exc_info=True) logger.error( f'Encountered unexpected {error.__class__.__name__}: "{error}"\n' f"Full error traceback logged to {LOG_FILEPATH}\n\n" + printer.dim( "For support, please create an issue at " "https://github.com/spectacles-ci/spectacles/issues" ) + "\n" ) sys.exit(1)
def wrapper(*args, **kwargs): try: return function(*args, **kwargs) except GenericValidationError as error: sys.exit(error.exit_code) except LookerApiError as error: logger.error(f"\n{error}\n\n" + printer.dim( "Run in verbose mode (-v) or check your log file to see the full " "response from the Looker API. " "For support, please create an issue at " "https://github.com/spectacles-ci/spectacles/issues") + "\n") looker_api_response = json.dumps(error.looker_api_response, indent=2) logger.debug( f"Spectacles received a {error.status} response code from " f"the Looker API with the following details: {looker_api_response}\n" ) sys.exit(error.exit_code) except SpectaclesException as error: logger.error(f"\n{error}\n\n" + printer.dim( "For support, please create an issue at " "https://github.com/spectacles-ci/spectacles/issues") + "\n") sys.exit(error.exit_code) except KeyboardInterrupt as error: logger.debug(error, exc_info=True) logger.info("Spectacles was manually interrupted.") sys.exit(1) except Exception as error: logger.debug(error, exc_info=True) logger.error( f'\nEncountered unexpected {error.__class__.__name__}: "{error}"\n' f"Full error traceback logged to file.\n\n" + printer.dim( "For support, please create an issue at " "https://github.com/spectacles-ci/spectacles/issues") + "\n") sys.exit(1)
def run_sql( log_dir, project, branch, explores, exclude, base_url, client_id, client_secret, port, api_version, mode, remote_reset, import_projects, concurrency, commit_ref, ) -> None: """Runs and validates the SQL for each selected LookML dimension.""" runner = Runner( base_url, project, branch, client_id, client_secret, port, api_version, remote_reset, import_projects, commit_ref, ) def iter_errors(lookml: List) -> Iterable: for item in lookml: if item.errored: yield item results = runner.validate_sql(explores, exclude, mode, concurrency) for test in sorted(results["tested"], key=lambda x: (x["model"], x["explore"])): message = f"{test['model']}.{test['explore']}" printer.print_validation_result(passed=test["passed"], source=message) errors = sorted( results["errors"], key=lambda x: (x["model"], x["explore"], x["metadata"].get("dimension")), ) if errors: for error in errors: printer.print_sql_error( model=error["model"], explore=error["explore"], message=error["message"], sql=error["metadata"]["sql"], log_dir=log_dir, dimension=error["metadata"].get("dimension"), lookml_url=error["metadata"].get("lookml_url"), ) if mode == "batch": logger.info( printer.dim( "\n\nTo determine the exact dimensions responsible for " f"{'this error' if len(errors) == 1 else 'these errors'}, " "you can re-run \nSpectacles in single-dimension mode, " "with `--mode single`.\n\nYou can also run this original " "validation with `--mode hybrid` to do this automatically." )) logger.info("") raise GenericValidationError else: logger.info("")