Esempio n. 1
0
    def update_session(self, project: str, branch: str) -> None:
        """Switches to a development mode session and checks out the desired branch.

        Args:
            project: Name of the Looker project to use.
            branch: Name of the Git branch to check out.

        """
        if branch == "master":
            logger.debug("Updating session to use production workspace")
            url = utils.compose_url(self.api_url, path=["session"])
            body = {"workspace_id": "production"}
            response = self.session.patch(url=url, json=body)
            try:
                response.raise_for_status()
            except requests.exceptions.HTTPError as error:
                details = utils.details_from_http_error(response)
                raise ApiConnectionError(
                    f"Unable to update session to production workspace.\n"
                    f"Looker API error encountered: {error}\n"
                    + "Message received from Looker's API: "
                    f'"{details}"'
                )

        else:
            logger.debug("Updating session to use development workspace")
            url = utils.compose_url(self.api_url, path=["session"])
            body = {"workspace_id": "dev"}
            response = self.session.patch(url=url, json=body)
            try:
                response.raise_for_status()
            except requests.exceptions.HTTPError as error:
                details = utils.details_from_http_error(response)
                raise ApiConnectionError(
                    f"Unable to update session to development workspace.\n"
                    f"Looker API error encountered: {error}\n"
                    + "Message received from Looker's API: "
                    f'"{details}"'
                )

            logger.debug(f"Setting Git branch to {branch}")
            url = utils.compose_url(
                self.api_url, path=["projects", project, "git_branch"]
            )
            body = {"name": branch}
            response = self.session.put(url=url, json=body)
            try:
                response.raise_for_status()
            except requests.exceptions.HTTPError as error:
                details = utils.details_from_http_error(response)
                raise ApiConnectionError(
                    f"Unable to checkout Git branch {branch}. "
                    "If you have uncommitted changes on the current branch, "
                    "please commit or revert them, then try again.\n\n"
                    f"Looker API error encountered: {error}\n"
                    + "Message received from Looker's API: "
                    f'"{details}"'
                )

            logger.info(f"Checked out branch {branch}")
Esempio n. 2
0
    def get_query_task_multi_results(self, query_task_ids: List[str]) -> JsonDict:
        """Returns query task results.

        If a ClientError or TimeoutError is received, attempts to retry.

        Args:
            query_task_ids: IDs for the query tasks running asynchronously.

        Returns:
            List[JsonDict]: JSON response from the query task.

        """
        # Using old-style string formatting so that strings are formatted lazily
        logger.debug(
            "Attempting to get results for %d query tasks", len(query_task_ids)
        )
        url = utils.compose_url(self.api_url, path=["query_tasks", "multi_results"])
        response = self.session.get(
            url=url, params={"query_task_ids": ",".join(query_task_ids)}
        )
        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as error:
            details = utils.details_from_http_error(response)
            raise ApiConnectionError(
                f"Looker API error encountered: {error}\n"
                + "Message received from Looker's API: "
                f'"{details}"'
            )
        return response.json()
Esempio n. 3
0
    def get_lookml_dimensions(self, model: str, explore: str) -> List[str]:
        """Gets all dimensions for an explore from the LookmlModel endpoint.

        Args:
            model: Name of LookML model to query.
            explore: Name of LookML explore to query.

        Returns:
            List[str]: Names of all the dimensions in the specified explore. Dimension
                names are returned in the format 'explore_name.dimension_name'.

        """
        logger.debug(f"Getting all dimensions from explore {explore}")
        url = utils.compose_url(
            self.api_url, path=["lookml_models", model, "explores", explore]
        )
        response = self.session.get(url=url)
        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as error:
            details = utils.details_from_http_error(response)
            raise ApiConnectionError(
                f'Unable to get dimensions for explore "{explore}".\n'
                f"Looker API error encountered: {error}\n"
                + "Message received from Looker's API: "
                f'"{details}"'
            )

        return response.json()["fields"]["dimensions"]
Esempio n. 4
0
    def run_lookml_test(self, project: str, model: str = None) -> List[JsonDict]:
        """Runs all LookML/data tests for a given project and model (optional)

        This command only runs tests in production, as the Looker API doesn't currently
        allow us to run data tests on a specific branch.

        Args:
            project: Name of the Looker project to use
            model: Optional name of the LookML model to restrict testing to

        Returns:
            List[JsonDict]: JSON response containing any LookML/data test errors

        """
        logger.debug(f"Running LookML tests for project {project}")
        url = utils.compose_url(
            self.api_url, path=["projects", project, "lookml_tests", "run"]
        )
        if model is not None:
            response = self.session.get(url=url, params={"model": model})
        else:
            response = self.session.get(url=url)

        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as error:
            raise ApiConnectionError(
                f"Failed to run data tests for project {project}\n"
                f'Error raised: "{error}"'
            )

        return response.json()
Esempio n. 5
0
    def all_lookml_tests(self, project: str) -> List[JsonDict]:
        """Gets all LookML/data tests for a given project.

        Args:
            project: Name of the Looker project to use

        Returns:
            List[JsonDict]: JSON response containing all LookML/data tests

        """
        logger.debug(f"Getting LookML tests for project {project}")
        url = utils.compose_url(
            self.api_url, path=["projects", project, "lookml_tests"]
        )
        response = self.session.get(url=url)

        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as error:
            raise ApiConnectionError(
                f"Failed to retrieve data tests for project {project}\n"
                f'Error raised: "{error}"'
            )

        return response.json()
Esempio n. 6
0
    def authenticate(self, client_id: str, client_secret: str,
                     api_version: float) -> None:
        """Logs in to Looker's API using a client ID/secret pair and an API version.

        Args:
            client_id: Looker API client ID.
            client_secret: Looker API client secret.
            api_version: Desired API version to use for requests.

        """
        logger.debug("Authenticating Looker API credentials")

        url = utils.compose_url(self.api_url, path=["login"])
        body = {"client_id": client_id, "client_secret": client_secret}
        response = self.session.post(url=url, data=body)
        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as error:
            details = utils.details_from_http_error(response)
            raise ApiConnectionError(
                f"Failed to authenticate to {url}\n"
                f"Attempted authentication with client ID {client_id}\n"
                f"Looker API error encountered: {error}\n" +
                "Message received from Looker's API: "
                f'"{details}"')

        access_token = response.json()["access_token"]
        self.session.headers = {"Authorization": f"token {access_token}"}

        logger.info(f"Connected using Looker API {api_version}")
Esempio n. 7
0
    def get_lookml_models(self) -> List[JsonDict]:
        """Gets all models and explores from the LookmlModel endpoint.

        Returns:
            List[JsonDict]: JSON response containing LookML models and explores.

        """
        logger.debug(f"Getting all models and explores from {self.base_url}")
        url = utils.compose_url(self.api_url, path=["lookml_models"])
        response = self.session.get(url=url)
        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as error:
            details = utils.details_from_http_error(response)
            raise ApiConnectionError(
                f"Unable to retrieve explores.\n"
                f"Looker API error encountered: {error}\n" +
                "Message received from Looker's API: "
                f'"{details}"')

        return response.json()
Esempio n. 8
0
    def get_looker_release_version(self) -> str:
        """Gets the version number of connected Looker instance.

        Returns:
            str: Looker instance release version number (e.g. 6.22.12)

        """
        logger.debug("Checking Looker instance release version")

        url = utils.compose_url(self.api_url, path=["versions"])

        response = self.session.get(url=url)
        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as error:
            details = utils.details_from_http_error(response)
            raise ApiConnectionError(
                "Failed to get Looker instance release version\n"
                f"Looker API error encountered: {error}\n" +
                "Message received from Looker's API: "
                f'"{details}"')

        return response.json()["looker_release_version"]