Source code for schrodinger.test.performance.client
import json
import requests
from requests.models import Response
import schrodinger.test.performance.exceptions as exceptions
import schrodinger.test.stu.client as stu_client
from schrodinger.test.performance import reporter
from schrodinger.test.stu import common
[docs]class PerformanceTestClient(stu_client._BaseClient):
[docs]    def __init__(self, username=None):
        super().__init__(username=username)
        self._productapi = self.item_uri('product')
        self._testapi = self.performance_uri('test')
[docs]    def getSingleEntityFromResponse(
        self,
        response: Response,
        exception_missing_key_message:
        str = "Response does not contain the 'objects' key",
        exception_mulitple_objects_msg:
        str = "Response contains multiple 'objects', expecting only one"
    ) -> dict:
        """
        Take a response object, extract JSON, validate its contents.
        Return a single object if exists, return None of zero objects found, raise BedResponse exception otherwise.
        """
        data = response.json()
        if 'objects' not in data:
            raise exceptions.BadResponse(exception_missing_key_message)
        objects = data['objects']
        if len(objects) == 1:
            return objects[0]
        elif len(objects) > 1:
            raise exceptions.BadResponse(exception_mulitple_objects_msg)
        else:
            return None
[docs]    def get_or_create(self, url: str, params: dict) -> str:
        """Get or create a resource matching the parameters."""
        response = self.get(url, params=params)
        entity = self.getSingleEntityFromResponse(response)
        if entity:
            return entity['resource_uri']
        response = self.post(
            url,
            data=json.dumps(params),
        )
        location = response.headers['location']
        return location.replace(common.BASE_URL, '')
[docs]    def get_or_create_test(self,
                           name: str,
                           description: str,
                           product_name: str,
                           scival=False):
        """
        Get or create a single test from the performance database.
        Setting `scival` to `True` will add the 'scival' tag when creating a new test.
        """
        params = dict(name=product_name)
        response = self.get(self._productapi,
                            params=params,
                            required_statuses=(200, 401, 404))
        username = stu_client.get_stu_username()
        no_product_msg = (
            f'No product named "{product_name}". See the list of product names '
            f'at {common.BASE_URL}/products. File a BLDMGR JIRA ticket if you '
            'need to add a product to STU. Please specify the name of the '
            'the product, the TL associated with the product, and the jira '
            'project which tracks tickets as part of the project.')
        if response.status_code == 404:
            raise exceptions.BadResponse(no_product_msg)
        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as http_error:
            if response.status_code == 401:
                raise exceptions.BadResponse(
                    f"{http_error}, please verify that the appropriate user is making this request: username='{username}'"
                )
            raise
        entity = self.getSingleEntityFromResponse(
            response, exception_missing_key_message=no_product_msg)
        if not entity:
            raise exceptions.BadResponse(no_product_msg)
        product = entity['resource_uri']
        product_id = reporter.resource_id(product)
        # Get an existing test:
        test_dict = dict(name=name, product=product_id)
        response = self.get(self._testapi, params=test_dict)
        entity = self.getSingleEntityFromResponse(response)
        if entity:
            return entity['resource_uri']
        # Create a new test:
        if not description:
            raise ValueError(
                "Description is required when uploading a new test.")
        test_dict['description'] = description
        if scival:
            test_dict['tags'] = ['scival']
        response = self.post(
            self._testapi,
            data=json.dumps(test_dict),
        )
        location = response.headers['location']
        return location.replace(common.BASE_URL, '')