Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_log_SQL(self):
with self.assertLogs(logger=logger, level="INFO") as cm:
func = MagicMock()
func.__name__ = "run_sql"
decorated_func = utils.log_duration(func)
decorated_func()
self.assertIn("INFO:spectacles:Completed SQL validation in", cm.output[0])
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 validate(self) -> Dict[str, Any]:
result = self.client.content_validation()
self.project.queried = True
for content in result["content_with_errors"]:
# Skip content dicts if they lack a `look` or `dashboard` key
try:
content_type = self._get_content_type(content)
except KeyError:
logger.warn(
"Warning: Skipping some content because it does not seem to be a "
"Dashboard or a Look."
)
logger.debug(f"The unidentified content received was: {content}")
continue
# If exclude_personal isn't specified, personal_folders list is empty
if content[content_type]["folder"]["id"] in self.personal_folders:
continue
else:
self._handle_content_result(content, content_type)
return self.project.get_results(validator="content")
def request(self, method: str, url: str, *args, **kwargs) -> requests.Response:
if self.access_token and self.access_token.expired:
logger.debug("Looker API access token has expired, requesting a new one")
self.authenticate()
return self.session.request(method, url, *args, **kwargs)
def print_header(text: str, line_width: int = LINE_WIDTH) -> None:
header = f" {text} ".center(line_width, "=")
logger.info(f"\n{header}\n")
def create_branch(self, project: str, branch: str, ref: str = "origin/master"):
"""Creates a branch in the given project.
Args:
project: Name of the Looker project to use.
branch: Name of the branch to create.
ref: The ref to create the branch from.
"""
logger.debug(
f"Creating branch '{branch}' on project '{project}' with ref '{ref}'"
)
body = {"name": branch, "ref": ref}
url = utils.compose_url(self.api_url, path=["projects", project, "git_branch"])
response = self.post(url=url, json=body, timeout=TIMEOUT_SEC)
try:
response.raise_for_status()
except requests.exceptions.HTTPError:
raise LookerApiError(
name="unable-to-create-branch",
title="Couldn't create new Git branch.",
status=response.status_code,
detail=(
f"Unable to create branch '{branch}' "
def validate(self) -> Dict[str, Any]:
result = self.client.content_validation()
self.project.queried = True
for content in result["content_with_errors"]:
# Skip content dicts if they lack a `look` or `dashboard` key
try:
content_type = self._get_content_type(content)
except KeyError:
logger.warn(
"Warning: Skipping some content because it does not seem to be a "
"Dashboard or a Look."
)
logger.debug(f"The unidentified content received was: {content}")
continue
# If exclude_personal isn't specified, personal_folders list is empty
if content[content_type]["folder"]["id"] in self.personal_folders:
continue
else:
self._handle_content_result(content, content_type)
return self.project.get_results(validator="content")
def branch_imported_projects(self):
logger.debug("Creating temporary branches in imported projects")
manifest = self.client.get_manifest(self.project)
local_dependencies = [p for p in manifest["imports"] if not p["is_remote"]]
for project in local_dependencies:
original_branch = self.client.get_active_branch(project["name"])
temp_branch = self.setup_temp_branch(project["name"], original_branch)
self.client.create_branch(project["name"], temp_branch)
self.client.update_branch(project["name"], temp_branch)
def timed_function(*args, **kwargs):
start_time = timeit.default_timer()
try:
result = fn(*args, **kwargs)
finally:
elapsed = timeit.default_timer() - start_time
elapsed_str = human_readable(elapsed)
message_detail = get_detail(fn.__name__)
logger.info(f"Completed {message_detail}validation in {elapsed_str}.\n")
return result
def _run_queries(self, queries: List[Query]) -> None:
"""Creates and runs queries with a maximum concurrency defined by query slots"""
QUERY_TASK_LIMIT = 250
while queries or self._running_queries:
if queries:
logger.debug(f"Starting a new loop, {len(queries)} queries queued")
self._fill_query_slots(queries)
query_tasks = self.get_running_query_tasks()[:QUERY_TASK_LIMIT]
logger.debug(f"Checking for results of {len(query_tasks)} query tasks")
for query_result in self._get_query_results(query_tasks):
self._handle_query_result(query_result)
time.sleep(0.5)