Пример #1
0
    def fetch(self, dataset):
        """
        Reads the dataset sub-objects from database
        Retrieves the list of Timeseries

        :param dataset: Dataset object
        :type dataset: Dataset

        :returns: the list of Timeseries composing the Dataset
        :rtype: list of Timeseries

        :raises TypeError: if name is not a Dataset
        :raises IkatsNotFoundError: if dataset not found in database
        """
        check_type(value=dataset,
                   allowed_types=Dataset,
                   var_name="dataset",
                   raise_exception=True)

        result = self.dm_client.dataset_read(dataset.name)
        ts = [
            Timeseries(tsuid=x['tsuid'], fid=x['funcId'], api=self.api)
            for x in result.get('ts_list', [])
        ]
        return ts
Пример #2
0
    def __init__(self, api, json_data=None):
        """
        Constructor

        :param api: see IkatsObject
        :param json_data: information provided by catalog to fill this input/parameter/output

        :type api: IkatsAPI
        :type json_data: dict
        """

        self.__desc = None
        self.__domain = None
        self.__label = None
        self.__name = None
        self.__order_index = None
        self.__dtype = None
        self.__default_value = None
        self.__rid = None

        self.__api = None
        self.api = api

        if json_data is not None:
            check_type(value=json_data, allowed_types=dict, var_name="json_data", raise_exception=True)

            self.desc = json_data.get("description", None)
            self.domain = json_data.get("domain", None)
            self.label = json_data.get("label", None)
            self.name = json_data.get("name", None)
            self.order_index = json_data.get("order_index", None)
            self.dtype = json_data.get("type", None)
            self.default_value = json_data.get("default_values", None)
Пример #3
0
    def delete(self, name, raise_exception=True):
        """
        Delete a table
        Returns a boolean status of the action (True means "OK", False means "errors occurred")

        :param name: the name of the table to delete
        :param raise_exception: Indicates if exceptions shall be raised (True, default) or not (False)

        :type name: str
        :type raise_exception: bool

        :returns: the status of deletion (True=deleted, False otherwise)
        :rtype: bool

        :raises IkatsNotFoundError: if table not found in database
        """
        check_type(value=name,
                   allowed_types=str,
                   var_name="name",
                   raise_exception=True)
        check_type(value=raise_exception,
                   allowed_types=bool,
                   var_name="raise_exception",
                   raise_exception=True)

        try:
            self.dm_client.table_delete(name=name)
        except IkatsException:
            if raise_exception:
                raise
            return False
        return True
Пример #4
0
    def get_type(self, name):
        """
        Get the metadata type if present in local cache.
        If cache is empty, fetch the data from database

        :param name: name of the metadata to get
        :type name: str

        :returns: the type of the value
        :rtype: DTYPE

        :raises IkatsNotFoundError: if metadata doesn't exist
        """

        # Input check
        check_type(value=name,
                   allowed_types=str,
                   var_name="name",
                   raise_exception=True)

        # Update metadata if empty
        if self.__data is None:
            self.fetch()

        # A metadata marked as 'deleted' shall not be returned
        if name not in self.__data or self.__data[name]["deleted"]:
            raise IkatsNotFoundError("Metadata '%s' not defined" % name)

        return self.__data[name]["dtype"]
Пример #5
0
    def get(self, name):
        """
        Reads the dataset information from database
        Retrieves description and list of Timeseries

        :param name: Dataset name
        :type name: str

        :returns: the retrieved Dataset object with Timeseries list filled
        :rtype: Dataset

        :raises TypeError: if *name* is not a Dataset
        :raises IkatsNotFoundError: if dataset not found in database
        """
        check_type(value=name,
                   allowed_types=str,
                   var_name="name",
                   raise_exception=True)

        result = self.dm_client.dataset_read(name)
        ts = [
            Timeseries(tsuid=x['tsuid'], fid=x['funcId'], api=self.api)
            for x in result.get('ts_list', [])
        ]
        description = result.get("description", "")
        return Dataset(api=self.api, name=name, desc=description, ts=ts)
Пример #6
0
    def is_json_valid(data, raise_exception=True):
        """
        Check if the provided JSON (as a dict) contains all necessary information to be considered valid

        :param data: the JSON as dict
        :param raise_exception: Indicates if exceptions shall be raised (True, default) or not (False)

        :type data: dict
        :type raise_exception: bool

        :return: the check status
        :rtype: bool

        :raises SchemaError: if JSON is invalid
        """
        check_type(value=data,
                   allowed_types=dict,
                   var_name="data",
                   raise_exception=True)

        try:
            TABLE_SCHEMA.validate(data=data)
            return True
        except SchemaError:
            if raise_exception:
                raise
            return False
Пример #7
0
    def delete(self, name):
        """
        Mark a metadata as 'deleted'
        The deletion will be trigger on remote side upon `Metadata.save()` action

        The marked metadata won't be accessible locally anymore
        However, the metadata can still be recreated again (using Metadata.set())

        :param name: Name of the metadata to delete
        :type name: str
        """
        # Input check
        check_type(value=name,
                   allowed_types=str,
                   var_name="name",
                   raise_exception=True)

        # Empty local database
        if self.__data is None:
            self.__data = dict()

        # Metadata is absent
        if name not in self.__data:
            self.__data[name] = dict()

        self.__data[name]["deleted"] = True
Пример #8
0
    def fetch(self, metadata):
        """
        Fetch and return metadata information about the Metadata object provided

        The returned dict has the following format:
        {
          'md1':{'value':'value1', 'dtype': 'dtype', 'deleted': False},
          'md2':{'value':'value2', 'dtype': 'dtype', 'deleted': False}
        }

        :param metadata: Metadata object containing a valid tsuid
        :type metadata: Metadata

        :returns: the object containing information about each metadata matching the TSUID.
        :rtype: dict

        :raises IkatsNotFoundError: if metadata doesn't exist
        """

        check_type(value=metadata,
                   allowed_types=Metadata,
                   raise_exception=True)
        result = self.dm_client.metadata_get_typed(
            ts_list=[metadata.tsuid])[metadata.tsuid]

        for md in result:
            # Converts MDType
            result[md]["dtype"] = result[md]["dtype"]
            # Flag metadata as "not deleted"
            result[md]["deleted"] = False

        return result
Пример #9
0
    def new(self, name=None, data=None):
        """
        Creates an empty table locally

        :param name: (optional) name of the Table
        :param data: (optional) data of the table (as a JSON)

        :type name: str or None
        :type data: dict or None

        :return: the Table object
        :rtype: Table

        :raises IkatsConflictError: if table already exist
        """
        check_type(value=name,
                   allowed_types=[str, None],
                   var_name="name",
                   raise_exception=True)
        check_type(value=data,
                   allowed_types=[dict, None],
                   var_name="data",
                   raise_exception=True)
        try:
            self.dm_client.table_read(name=name)
        except IkatsNotFoundError:
            return Table(api=self.api, name=name, data=data)
        raise IkatsConflictError(
            "Table already exist. Try using `get()` method")
Пример #10
0
    def list(self, name=None, strict=True):
        """
        List all tables
        If name is specified, filter by name
        name can contains "*", this character is considered as "any chars" (equivalent to regexp /.*/)

        :param name: name to find
        :param strict: consider name without any wildcards

        :type name: str or None
        :type strict: bool

        :returns: the list of tables matching the requirements
        :rtype: list
        """
        check_type(value=name,
                   allowed_types=[str, None],
                   var_name="name",
                   raise_exception=True)
        check_type(value=strict,
                   allowed_types=bool,
                   var_name="strict",
                   raise_exception=True)

        return self.dm_client.table_list(name=name, strict=strict)
Пример #11
0
    def get_func_id_from_tsuid(self, tsuid):
        """
        Retrieve the functional identifier resource associated to the tsuid param.
        The resource returned aggregates original tsuid and retrieved fundId.

        :param tsuid: one tsuid value
        :type tsuid: str

        :returns: retrieved functional identifier resource
        :rtype: dict having following keys defined:
          - 'tsuid'
          - and 'funcId'

        :raises exception:
            - TypeError: if tsuid is not a str OR status_code 400 (bad request) OR unexpected http status_code
            - ValueError: mismatched result: http status_code 404:  not found
            - ServerError: http status_code for server errors: 500 <= status_code < 600
        """
        check_type(value=tsuid,
                   allowed_types=str,
                   var_name="tsuid",
                   raise_exception=True)

        response = self.send(
            root_url=self.session.dm_url + self.root_url,
            verb=GenericClient.VERB.GET,
            template=TEMPLATES['get_one_functional_identifier'],
            uri_params={'tsuid': tsuid},
            data=None,
            files=None)

        check_http_code(response)

        return response.json['funcId']
Пример #12
0
    def get_fid(self, tsuid):
        """
        Get a functional ID from its TSUID

        :param tsuid: TSUID identifying the TS

        :type tsuid: str

        :raises TypeError: if *tsuid* not a str
        :raises ValueError: if *tsuid* is empty
        :raises ValueError: if *tsuid* doesn't have a FID
        """

        # Checks inputs
        check_type(value=tsuid,
                   allowed_types=str,
                   var_name="tsuid",
                   raise_exception=True)

        if tsuid == "":
            self.session.log.error("tsuid must not be empty")
            raise ValueError("tsuid must not be empty")

        response = self.send(root_url=self.session.dm_url + self.root_url,
                             verb=GenericClient.VERB.GET,
                             template=TEMPLATES['get_fid'],
                             uri_params={'tsuid': tsuid})

        # in case of success, web app returns 2XX
        if response.status_code == 200:
            if response.json != '{}':
                fid = response.json['funcId']
                return fid
            raise IndexError("No FID for TSUID [%s]" % tsuid)
        raise ValueError("No FID for TSUID [%s]" % tsuid)
Пример #13
0
 def desc(self, value):
     check_type(value=value,
                allowed_types=[str, None],
                var_name="description",
                raise_exception=True)
     self.__desc = value
     if value is None:
         self.__desc = ""
Пример #14
0
 def session(self, value):
     check_type(value=value,
                allowed_types=IkatsSession,
                var_name="session",
                raise_exception=True)
     if value.rs is None:
         raise ValueError(
             "Requests Session not set in provided IKATS session")
     self.__session = value
Пример #15
0
 def name(self, value):
     check_type(value=value,
                allowed_types=[str, None],
                var_name="name",
                raise_exception=True)
     if value is not None:
         check_is_valid_ds_name(value=value, raise_exception=True)
         if self.__name != value:
             self.__flag_ts_loaded = False
             self.__name = value
Пример #16
0
    def port(self, value):
        check_type(value=value,
                   allowed_types=[int, str, float, None],
                   var_name="port",
                   raise_exception=True)

        if int(value) <= 0 or int(value) >= 65535:
            raise ValueError("Port must be within ]0;65535] (got %s)" % value)

        self.__port = int(value)
Пример #17
0
    def ts_delete(self, tsuid, raise_exception=True):
        """
        Remove timeseries from database
        return bool status except if raise_exception is set to True.
        In this case, return True or raise the corresponding exception

        Corresponding web app resource operation: **removeTimeSeries**
        which deletes also all information related to other objects like Metadata, Dataset

        :param tsuid: tsuid of the timeseries to remove
        :param raise_exception: set to True to raise exceptions

        :type tsuid: str
        :type raise_exception: bool

        :returns: the action status (True if deleted, False otherwise)
        :rtype: bool

        :raises TypeError: if *tsuid* is not a str
        :raises IkatsNotFoundError: if *tsuid* is not found on server
        :raises IkatsConflictError: if *tsuid* belongs to -at least- one dataset
        :raises SystemError: if any other unhandled error occurred
        """

        # Checks inputs
        check_type(value=tsuid,
                   allowed_types=str,
                   var_name="tsuid",
                   raise_exception=True)

        response = self.send(root_url=self.session.dm_url + self.root_url,
                             verb=GenericClient.VERB.DELETE,
                             template=TEMPLATES['remove_ts'],
                             uri_params={'tsuid': tsuid})

        if response.status_code == 204:
            # Timeseries has been successfully deleted
            result = True
        elif response.status_code == 404:
            # Timeseries not found in database
            if raise_exception:
                raise IkatsNotFoundError(
                    "Timeseries %s not found in database" % tsuid)
            result = False
        elif response.status_code == 409:
            # Timeseries linked to existing dataset
            if raise_exception:
                raise IkatsConflictError(
                    "%s belongs to -at least- one dataset" % tsuid)
            result = False
        else:
            if raise_exception:
                raise SystemError("An unhandled error occurred")
            result = False
        return result
Пример #18
0
 def name(self, value):
     check_type(value=value,
                allowed_types=[str, None],
                var_name="name",
                raise_exception=True)
     if value is not None:
         self.__name = value
     if self.__data is not None:
         try:
             self.__data['table_desc']['name'] = value
         except KeyError:
             pass
Пример #19
0
    def tsuid(self, value):
        """
        Setter for tsuid

        This setter shouldn't be used manually
        """
        check_type(value=value,
                   allowed_types=[str, None],
                   var_name="tsuid",
                   raise_exception=True)
        if self.__tsuid != value:
            self.__tsuid = value
            # Update Metadata link
            self.metadata.tsuid = value
Пример #20
0
    def data(self, value):
        check_type(value=value,
                   allowed_types=[dict, None],
                   var_name="name",
                   raise_exception=True)
        if value is not None:
            self.is_json_valid(data=value)
            try:
                self.name = value['table_desc']['name']
            except KeyError:
                # The data doesn't contain the name, just skip this part
                pass

        self.__data = value
Пример #21
0
    def import_fid(self, tsuid, fid):
        """
        Import a functional ID into database

        :param tsuid: TSUID identifying the TS
        :param fid: Functional identifier

        :type tsuid: str
        :type fid: str

        :raises TypeError: if *tsuid* not a str
        :raises TypeError: if *fid* not a str

        :raises ValueError: if *tsuid* is empty
        :raises ValueError: if *fid* is empty
        :raises IkatsConflictError: if *fid* exists
        :raises SystemError: if another issue occurs
        """

        # Checks inputs
        check_is_fid_valid(fid=fid, raise_exception=True)
        check_type(value=tsuid,
                   allowed_types=str,
                   var_name="tsuid",
                   raise_exception=True)
        if tsuid == "":
            raise ValueError("tsuid must not be empty")

        response = self.send(root_url=self.session.dm_url + self.root_url,
                             verb=GenericClient.VERB.POST,
                             template=TEMPLATES['import_fid'],
                             uri_params={
                                 'tsuid': tsuid,
                                 'fid': fid
                             })

        # In case of success, web app returns 2XX
        if response.status_code == 200:
            pass
        elif response.status_code == 409:
            raise IkatsConflictError(
                "TSUID:%s - FID already exists (not updated) %s" %
                (tsuid, fid))
        else:
            self.session.log.warning("TSUID:%s - FID %s not created (got %s)",
                                     tsuid, fid, response.status_code)
            raise SystemError("TSUID:%s - FID %s not created (got %s)" %
                              (tsuid, fid, response.status_code))
Пример #22
0
 def ts(self, value):
     check_type(value=value,
                allowed_types=[list, None],
                var_name="ts",
                raise_exception=True)
     if value is not None:
         for ts in value:
             check_type(value=ts,
                        allowed_types=[str, Timeseries],
                        var_name="ts",
                        raise_exception=True)
         self.__ts = [
             x if isinstance(x, Timeseries) else Timeseries(tsuid=x,
                                                            api=self.api)
             for x in value
         ]
Пример #23
0
    def dataset_delete(self, name, deep=False):
        """
        Remove data_set from base

        Corresponding web app resource operation: **removeDataSet**

        :param name: name of the dataset to delete
        :type name: str

        :param deep: true to deeply remove dataset (TSUID and metadata erased)
        :type deep: boolean

        :returns: the response body
        :rtype: str

        .. note::
           Removing an unknown dataset results in a successful operation (server constraint)
           The only possible errors may come from server (HTTP status_code code 5xx)

        :raises TypeError: if *name* is not a str
        :raises TypeError: if *deep* is not a bool
        """

        # Checks inputs
        check_type(value=name,
                   allowed_types=str,
                   var_name="name",
                   raise_exception=True)
        check_is_valid_ds_name(value=name, raise_exception=True)
        check_type(value=deep,
                   allowed_types=bool,
                   var_name="deep",
                   raise_exception=True)

        template = 'dataset_remove'
        if deep:
            template = 'dataset_deep_remove'
        response = self.send(root_url=self.session.dm_url + self.root_url,
                             verb=GenericClient.VERB.DELETE,
                             template=TEMPLATES[template],
                             uri_params={'name': name})

        if response.status_code == 404:
            raise IkatsNotFoundError("Dataset %s not found in database" % name)
        return response.text
Пример #24
0
    def delete(self, ts, raise_exception=True):
        """
        Delete the data corresponding to a *ts* object and all associated metadata

        Note that if timeseries belongs to a dataset it will not be removed

        Returns a boolean status of the action (True means "OK", False means "errors occurred")

        :param ts: tsuid of the timeseries or Timeseries Object to remove
        :param raise_exception: (optional) Indicates if IKATS exceptions shall be raised (True, default) or not (False)

        :type ts: str or Timeseries
        :type raise_exception: bool

        :returns: the status of the action
        :rtype: bool

        :raises TypeError: if *ts* is not a str nor a Timeseries
        :raises IkatsNotFoundError: if timeseries is not found on server
        :raises IkatsConflictError: if timeseries belongs to -at least- one dataset
        """

        check_type(value=ts,
                   allowed_types=[str, Timeseries],
                   var_name="ts",
                   raise_exception=True)

        tsuid = ts

        if isinstance(ts, Timeseries):
            if ts.tsuid is not None:
                tsuid = ts.tsuid
            elif ts.fid is not None:
                try:
                    tsuid = self.dm_client.get_tsuid_from_fid(fid=ts.fid)
                except IkatsException:
                    if raise_exception:
                        raise
                    return False
            else:
                raise ValueError(
                    "Timeseries object shall have set at least tsuid or fid")

        return self.dm_client.ts_delete(tsuid=tsuid,
                                        raise_exception=raise_exception)
Пример #25
0
    def dataset_read(self, name):
        """
        Retrieve the details of a Dataset provided in arguments

        Corresponding web app resource operation: **getDataSet**

        :param name: name of the dataset to request TS list from
        :type name: str

        :return:
           information about ts_list and description
           * *ts_list* is the list of TS matching the data_set
           * *description* is the description sentence of the dataset
        :rtype: dict

        :raises TypeError: if name is not a str
        :raises IkatsNotFoundError: if dataset doesn't exist in database
        """

        # Checks inputs
        check_type(value=name,
                   allowed_types=str,
                   var_name="name",
                   raise_exception=True)

        ret = {'ts_list': [], 'description': None}

        response = self.send(root_url=self.session.dm_url + self.root_url,
                             verb=GenericClient.VERB.GET,
                             template=TEMPLATES['dataset_read'],
                             uri_params={'name': name})

        is_404(response=response,
               msg="Dataset %s not found in database" % name)

        if response.status_code == 200:
            if 'fids' in response.json:
                ret['ts_list'] = response.json['fids']

            if 'description' in response.json:
                ret['description'] = response.json['description']

            return ret
        raise SystemError("Something wrong happened")
Пример #26
0
    def search_functional_identifiers(self, criterion_type, criteria_list):
        """
        Retrieve the list of functional identifier records.
        Each resource record aggregates one tsuid and associated fundId.

        Note: partial match will not raise error, contrary to empty match.

        :param criterion_type: defines criterion applicable to this search
        :type criterion_type: str value accepted by server.
          ex: 'tsuids' or 'funcIds'
        :param criteria_list: non empty list of possible values for the criterion type
        :type criteria_list: list of str

        :returns: matching list of functional identifier resources: dict having following keys defined:
            - 'tsuid',
            - and 'funcId'
        :rtype: list of dict

        :raises exception:
          - TypeError: if unexpected arguments OR status_code 400 (bad request) OR unexpected http status_code
          - ValueError: mismatched result: http status_code 404:  not found
          - ServerError: http status_code for server errors: 500 <= status_code < 600
        """
        check_type(value=criterion_type,
                   allowed_types=str,
                   var_name="criterion_type",
                   raise_exception=True)
        check_type(value=criteria_list,
                   allowed_types=list,
                   var_name="criteria_list",
                   raise_exception=True)

        my_filter = dict()
        my_filter[criterion_type] = criteria_list

        response = self.send(
            root_url=self.session.dm_url + self.root_url,
            verb=GenericClient.VERB.POST,
            template=TEMPLATES['search_functional_identifier_list'],
            data=my_filter,
            files=None)
        check_http_code(response)

        return response.json
Пример #27
0
    def delete(self, raise_exception=True):
        """
        Remove the table from database but keep the local object
        Returns a boolean status of the action (True means "OK", False means "errors occurred")

        :param raise_exception: Indicates if exceptions shall be raised (True, default) or not (False)
        :type raise_exception: bool

        :returns: the status of the action
        :rtype: bool

        :raises IkatsNotFoundError: if table not found in database
        """
        check_type(value=raise_exception,
                   allowed_types=bool,
                   var_name="raise_exception",
                   raise_exception=True)
        return self.api.table.delete(name=self.name,
                                     raise_exception=raise_exception)
Пример #28
0
    def delete(self, name, deep=False, raise_exception=True):
        """
        Remove dataset from database
        Returns a boolean status of the action (True means "OK", False means "errors occurred")

        :param name: Dataset name to delete
        :param deep: true to deeply remove dataset (tsuid and metadata erased)
        :param raise_exception: Indicates if exceptions shall be raised (True, default) or not (False)

        :type name: str or Dataset
        :type deep: bool
        :type raise_exception: bool

        :returns: the status of the action
        :rtype: bool

        :raises TypeError: if *name* is not a str
        :raises TypeError: if *deep* is not a bool
        :raises ValueError: if *name* is a valid name
        :raises IkatsNotFoundError: if dataset not found in database
        """
        check_type(value=deep,
                   allowed_types=[bool, None],
                   var_name="deep",
                   raise_exception=True)
        check_type(value=name,
                   allowed_types=[str, Dataset],
                   var_name="name",
                   raise_exception=True)

        if isinstance(name, Dataset):
            name = name.name

        check_is_valid_ds_name(value=name, raise_exception=True)

        try:
            self.dm_client.dataset_delete(name=name, deep=deep)
        except IkatsException:
            if raise_exception:
                raise
            return False
        return True
Пример #29
0
    def get(self, name):
        """
        Reads the data blob content: for the unique table identified by id.

        :param name: the id key of the raw table to get data from
        :type name: str

        :returns: the content data stored.
        :rtype: bytes or str or object

        :raises IkatsNotFoundError: no resource identified by ID
        :raises IkatsException: any other error
        """
        check_type(value=name,
                   allowed_types=str,
                   var_name="name",
                   raise_exception=True)

        data = self.dm_client.table_read(name=name)
        return Table(api=self.api, name=name, data=data)
Пример #30
0
    def save(self, raise_exception=True):
        """
        Save the table to database (creation only, no update available)
        Returns a boolean status of the action (True means "OK", False means "errors occurred")

        :param raise_exception: Indicates if exceptions shall be raised (True, default) or not (False)
        :type raise_exception: bool

        :returns: the status of the action
        :rtype: bool

        :raises IkatsConflictError: if Table name already exists in database
        """
        check_type(value=raise_exception,
                   allowed_types=bool,
                   var_name="raise_exception",
                   raise_exception=True)
        return self.api.table.save(data=self.data,
                                   name=self.name,
                                   raise_exception=raise_exception)