Exemplo n.º 1
0
    def __init__(
            self,
            name: str,
            dimension_name: str,
            elements: Optional[Iterable['Element']] = None,
            element_attributes: Optional[Iterable['ElementAttribute']] = None,
            edges: Optional['Dict'] = None,
            subsets: Optional[Iterable[str]] = None,
            structure: Optional[int] = None,
            default_member: Optional[str] = None):

        self._name = name
        self._dimension_name = None
        self.dimension_name = dimension_name
        self._elements = CaseAndSpaceInsensitiveDict()
        if elements:
            for elem in elements:
                self._elements[elem.name] = elem
        self._element_attributes = list(
            element_attributes) if element_attributes else []
        self._edges = CaseAndSpaceInsensitiveTuplesDict(
            edges) if edges else CaseAndSpaceInsensitiveTuplesDict()
        self._subsets = list(subsets) if subsets else []
        # balanced is true, false or None (in versions < TM1 11)
        self._balanced = False if not structure else structure == 0
        self._default_member = default_member
Exemplo n.º 2
0
 def __init__(self, name, dimension_name, elements=None, element_attributes=None,
              edges=None, subsets=None, structure=None, default_member=None):
     self._name = name
     self._dimension_name = dimension_name
     self._elements = CaseAndSpaceInsensitiveDict()
     if elements:
         for elem in elements:
             self._elements[elem.name] = elem
     self._element_attributes = element_attributes if element_attributes else []
     self._edges = CaseAndSpaceInsensitiveTuplesDict(edges) if edges else CaseAndSpaceInsensitiveTuplesDict()
     self._subsets = subsets if subsets else []
     # balanced is true, false or None (in versions < TM1 11)
     self._balanced = structure if not structure else structure == 0
     self._default_member = default_member
Exemplo n.º 3
0
    def update_element_attributes(self, hierarchy: Hierarchy, **kwargs):
        """ Update the elementattributes of a hierarchy

        :param hierarchy: Instance of TM1py.Hierarchy
        :return:
        """
        # get existing attributes first
        existing_element_attributes = self.elements.get_element_attributes(
            dimension_name=hierarchy.dimension_name,
            hierarchy_name=hierarchy.name,
            **kwargs)
        existing_element_attributes = CaseAndSpaceInsensitiveDict(
            {ea.name: ea
             for ea in existing_element_attributes})

        attributes_to_create = list()
        attributes_to_delete = list()
        attributes_to_update = list()

        for element_attribute in hierarchy.element_attributes:
            if element_attribute.name not in existing_element_attributes:
                attributes_to_create.append(element_attribute)
                continue

            existing_element_attribute = existing_element_attributes[
                element_attribute.name]
            if not existing_element_attribute.attribute_type == element_attribute.attribute_type:
                attributes_to_update.append(element_attribute)
                continue

        for existing_element_attribute in existing_element_attributes:
            if existing_element_attribute not in CaseAndSpaceInsensitiveSet(
                [ea.name for ea in hierarchy.element_attributes]):
                attributes_to_delete.append(existing_element_attribute)

        for element_attribute in attributes_to_create:
            self.elements.create_element_attribute(
                dimension_name=hierarchy.dimension_name,
                hierarchy_name=hierarchy.name,
                element_attribute=element_attribute,
                **kwargs)

        for element_attribute in attributes_to_delete:
            self.elements.delete_element_attribute(
                dimension_name=hierarchy.dimension_name,
                hierarchy_name=hierarchy.name,
                element_attribute=element_attribute,
                **kwargs)

        for element_attribute in attributes_to_update:
            self.elements.delete_element_attribute(
                dimension_name=hierarchy.dimension_name,
                hierarchy_name=hierarchy.name,
                element_attribute=element_attribute.name,
                **kwargs)
            self.elements.create_element_attribute(
                dimension_name=hierarchy.dimension_name,
                hierarchy_name=hierarchy.name,
                element_attribute=element_attribute,
                **kwargs)
Exemplo n.º 4
0
    def test_ne(self):
        _map = CaseAndSpaceInsensitiveDict()
        _map["key 1"] = "wrong"
        _map["key 2"] = "value2"
        _map["key3"] = "value3"
        self.assertNotEqual(self.map, _map)

        _map = CaseAndSpaceInsensitiveDict()
        _map["key1"] = "value1"
        _map["key 2"] = "wrong"
        _map["key3"] = "value3"
        self.assertNotEqual(self.map, _map)

        _map = CaseAndSpaceInsensitiveDict()
        _map["key1"] = "value1"
        _map["key2"] = "value2"
        _map["key4"] = "value4"
        self.assertNotEqual(self.map, _map)
Exemplo n.º 5
0
 def __init__(self,
              name,
              dimension_name,
              elements=None,
              element_attributes=None,
              edges=None,
              subsets=None,
              default_member=None):
     self._name = name
     self._dimension_name = dimension_name
     self._elements = CaseAndSpaceInsensitiveDict()
     if elements:
         for elem in elements:
             self._elements[elem.name] = elem
     self._element_attributes = element_attributes if element_attributes else []
     self._edges = edges if edges else CaseAndSpaceInsensitiveTuplesDict()
     self._subsets = subsets if subsets else []
     self._default_member = default_member
Exemplo n.º 6
0
from TM1py import TM1Service
from TM1py.Utils.Utils import CaseAndSpaceInsensitiveDict

import methods
from utils import set_current_directory

METHODS = CaseAndSpaceInsensitiveDict({
    "IRR": methods.irr,
    "NPV": methods.npv,
    "STDEV": methods.stdev,
    "STDEV_P": methods.stdev_p,
    "FV": methods.fv,
    "FV_SCHEDULE": methods.fv_schedule,
    "PV": methods.pv,
    "XNPV": methods.xnpv,
    "PMT": methods.pmt,
    "PPMT": methods.ppmt,
    "MIRR": methods.mirr,
    "XIRR": methods.xirr,
    "NPER": methods.nper,
    "RATE": methods.rate,
    "EFFECT": methods.effect,
    "NOMINAL": methods.nominal,
    "SLN": methods.sln
})

APP_NAME = "CubeCalc"
CURRENT_DIRECTORY = set_current_directory()
LOGFILE = os.path.join(CURRENT_DIRECTORY, APP_NAME + ".log")
CONFIG = os.path.join(CURRENT_DIRECTORY, "config.ini")
Exemplo n.º 7
0
    def get_message_log_entries(self,
                                reverse: bool = True,
                                since: datetime = None,
                                until: datetime = None,
                                top: int = None,
                                logger: str = None,
                                level: str = None,
                                msg_contains: Iterable = None,
                                msg_contains_operator: str = 'and',
                                **kwargs) -> Dict:
        """
        :param reverse: Boolean
        :param since: of type datetime. If it doesn't have tz information, UTC is assumed.
        :param until: of type datetime. If it doesn't have tz information, UTC is assumed.
        :param top: Integer
        :param logger: string, eg TM1.Server, TM1.Chore, TM1.Mdx.Interface, TM1.Process
        :param level: string, ERROR, WARNING, INFO, DEBUG, UNKNOWN
        :param msg_contains: iterable, find substring in log message; list of substrings will be queried as AND statement
        :param msg_contains_operator: 'and' or 'or'

        :param kwargs:
        :return: Dict of server log
        """
        msg_contains_operator = msg_contains_operator.strip().lower()
        if msg_contains_operator not in ("and", "or"):
            raise ValueError(
                "'msg_contains_operator' must be either 'AND' or 'OR'")

        reverse = 'desc' if reverse else 'asc'
        url = '/api/v1/MessageLogEntries?$orderby=TimeStamp {}'.format(reverse)

        if since or until or logger or level or msg_contains:
            log_filters = []

            if since:
                # If since doesn't have tz information, UTC is assumed
                if not since.tzinfo:
                    since = self.utc_localize_time(since)
                log_filters.append(
                    format_url("TimeStamp ge {}",
                               since.strftime("%Y-%m-%dT%H:%M:%SZ")))

            if until:
                # If until doesn't have tz information, UTC is assumed
                if not until.tzinfo:
                    until = self.utc_localize_time(until)
                log_filters.append(
                    format_url("TimeStamp le {}",
                               until.strftime("%Y-%m-%dT%H:%M:%SZ")))

            if logger:
                log_filters.append(format_url("Logger eq '{}'", logger))

            if level:
                level_dict = CaseAndSpaceInsensitiveDict({
                    'ERROR': 1,
                    'WARNING': 2,
                    'INFO': 3,
                    'DEBUG': 4,
                    'UNKNOWN': 5
                })
                level_index = level_dict.get(level)
                if level_index:
                    log_filters.append("Level eq {}".format(level_index))

            if msg_contains:
                if isinstance(msg_contains, str):
                    log_filters.append(
                        format_url("contains(toupper(Message),toupper('{}'))",
                                   msg_contains))
                else:
                    msg_filters = [
                        format_url("contains(toupper(Message),toupper('{}'))",
                                   wildcard) for wildcard in msg_contains
                    ]
                    log_filters.append("({})".format(
                        f" {msg_contains_operator} ".join(msg_filters)))

            url += "&$filter={}".format(" and ".join(log_filters))

        if top:
            url += '&$top={}'.format(top)

        response = self._rest.GET(url, **kwargs)
        return response.json()['value']
Exemplo n.º 8
0
 def remove_all_elements(self):
     self._elements = CaseAndSpaceInsensitiveDict()
     self.remove_all_edges()
Exemplo n.º 9
0
class Hierarchy(TM1Object):
    """ Abstraction of TM1 Hierarchy
        Requires reference to a Dimension

        Elements modeled as a Dictionary where key is the element name and value an instance of TM1py.Element
        {
            'US': instance of TM1py.Element,
            'CN': instance of TM1py.Element,
            'AU': instance of TM1py.Element
        }

        ElementAttributes of type TM1py.Objects.ElementAttribute

        Edges are represented as a TM1py.Utils.CaseAndSpaceInsensitiveTupleDict: 
        {
            (parent1, component1) : 10,
            (parent1, component2) : 30
        }

        Subsets is list of type TM1py.Subset

    """
    def __init__(
            self,
            name: str,
            dimension_name: str,
            elements: Optional[Iterable['Element']] = None,
            element_attributes: Optional[Iterable['ElementAttribute']] = None,
            edges: Optional['Dict'] = None,
            subsets: Optional[Iterable[str]] = None,
            structure: Optional[int] = None,
            default_member: Optional[str] = None):

        self._name = name
        self._dimension_name = None
        self.dimension_name = dimension_name
        self._elements = CaseAndSpaceInsensitiveDict()
        if elements:
            for elem in elements:
                self._elements[elem.name] = elem
        self._element_attributes = list(
            element_attributes) if element_attributes else []
        self._edges = CaseAndSpaceInsensitiveTuplesDict(
            edges) if edges else CaseAndSpaceInsensitiveTuplesDict()
        self._subsets = list(subsets) if subsets else []
        # balanced is true, false or None (in versions < TM1 11)
        self._balanced = False if not structure else structure == 0
        self._default_member = default_member

    @classmethod
    def from_dict(cls, hierarchy_as_dict: Dict) -> 'Hierarchy':
        # Build the Dictionary for the edges
        edges = CaseAndSpaceInsensitiveTuplesDict({
            (edge['ParentName'], edge['ComponentName']): edge['Weight']
            for edge in hierarchy_as_dict['Edges']
        })

        return cls(name=hierarchy_as_dict['Name'],
                   dimension_name=hierarchy_as_dict['UniqueName']
                   [1:hierarchy_as_dict['UniqueName'].find("].[")],
                   elements=[
                       Element.from_dict(elem)
                       for elem in hierarchy_as_dict['Elements']
                   ],
                   element_attributes=[
                       ElementAttribute(ea['Name'], ea['Type'])
                       for ea in hierarchy_as_dict['ElementAttributes']
                   ],
                   edges=edges,
                   subsets=[
                       subset['Name']
                       for subset in hierarchy_as_dict['Subsets']
                   ],
                   structure=hierarchy_as_dict['Structure']
                   if 'Structure' in hierarchy_as_dict else None,
                   default_member=hierarchy_as_dict['DefaultMember']['Name']
                   if hierarchy_as_dict['DefaultMember'] else None)

    @property
    def name(self) -> str:
        return self._name

    @name.setter
    def name(self, value: str):
        self._name = value

    @property
    def dimension_name(self) -> str:
        return self._dimension_name

    @dimension_name.setter
    def dimension_name(self, dimension_name: str):
        self._dimension_name = dimension_name

    @property
    def elements(self) -> CaseAndSpaceInsensitiveDict:
        return self._elements

    @property
    def element_attributes(self) -> List[ElementAttribute]:
        return self._element_attributes

    @property
    def edges(self) -> 'CaseAndSpaceInsensitiveTuplesDict':
        return self._edges

    @property
    def subsets(self) -> List[str]:
        return self._subsets

    @property
    def balanced(self) -> bool:
        return self._balanced

    @property
    def default_member(self) -> str:
        return self._default_member

    @property
    def body(self) -> str:
        return json.dumps(self._construct_body())

    @property
    def body_as_dict(self) -> Dict:
        return self._construct_body()

    def contains_element(self, element_name: str) -> bool:
        return element_name in self._elements

    def get_element(self, element_name: str) -> Element:
        if element_name in self._elements:
            return self._elements[element_name]
        else:
            raise ValueError("Element: {} not found in Hierarchy: {}".format(
                element_name, self.name))

    def add_element(self, element_name: str,
                    element_type: Union[str, Element.Types]):
        if element_name in self._elements:
            raise ValueError("Element name must be unique")

        self._elements[element_name] = Element(name=element_name,
                                               element_type=element_type)

    def update_element(self, element_name: str,
                       element_type: Union[str, Element.Types]):
        self._elements[element_name].element_type = element_type

    def remove_element(self, element_name: str):
        if element_name not in self._elements:
            return
        del self._elements[element_name]
        self.remove_edges_related_to_element(element_name=element_name)

    def remove_all_elements(self):
        self._elements = CaseAndSpaceInsensitiveDict()
        self.remove_all_edges()

    def add_edge(self, parent: str, component: str, weight: int):
        self._edges[(parent, component)] = weight

    def update_edge(self, parent: str, component: str, weight: int):
        self._edges[(parent, component)] = weight

    def remove_edge(self, parent: str, component: str):
        if (parent, component) in self.edges:
            del self.edges[(parent, component)]

    def remove_edges(self, edges: Iterable[Tuple[str, str]]):
        for edge in edges:
            self.remove_edge(*edge)

    def remove_all_edges(self):
        self._edges = CaseAndSpaceInsensitiveTuplesDict()

    def remove_edges_related_to_element(self, element_name: str):
        element_name_adjusted = lower_and_drop_spaces(element_name)
        edges_to_remove = set()
        for edge in self._edges.adjusted_keys():
            if element_name_adjusted in edge:
                edges_to_remove.add(edge)
        self.remove_edges(edges=edges_to_remove)

    def add_element_attribute(self, name: str, attribute_type: str):
        attribute = ElementAttribute(name, attribute_type)
        if attribute not in self.element_attributes:
            self.element_attributes.append(attribute)

    def remove_element_attribute(self, name: str):
        self._element_attributes = [
            element_attribute for element_attribute in self.element_attributes
            if
            not case_and_space_insensitive_equals(element_attribute.name, name)
        ]

    def _construct_body(self,
                        element_attributes: Optional[bool] = False) -> Dict:
        """
        With TM1 10.2.2 Hierarchy and Element Attributes can't be created in one batch
        -> https://www.ibm.com/developerworks/community/forums/html/threadTopic?id=d91f3e0e-d305-44db-ac02-2fdcbee00393
        Thus, no need to have the ElementAttribute included in the JSON

        :param element_attributes: Only include element_attributes in body if explicitly asked for
        :return:
        """

        body_as_dict = collections.OrderedDict()
        body_as_dict['Name'] = self._name
        body_as_dict['Elements'] = []
        body_as_dict['Edges'] = []

        for element in self._elements.values():
            body_as_dict['Elements'].append(element.body_as_dict)
        for edge in self._edges:
            edge_as_dict = collections.OrderedDict()
            edge_as_dict['ParentName'] = edge[0]
            edge_as_dict['ComponentName'] = edge[1]
            edge_as_dict['Weight'] = self._edges[edge]
            body_as_dict['Edges'].append(edge_as_dict)
        if element_attributes:
            body_as_dict['ElementAttributes'] = [
                element_attribute.body_as_dict
                for element_attribute in self._element_attributes
            ]
        return body_as_dict

    def __iter__(self):
        return iter(self._elements.values())

    def __len__(self):
        return len(self._elements)

    def __contains__(self, item):
        return self.contains_element(item)

    def __getitem__(self, item):
        return self.get_element(item)
Exemplo n.º 10
0
class Hierarchy(TM1Object):
    """ Abstraction of TM1 Hierarchy
        Requires reference to a Dimension

        Elements modeled as a Dictionary where key is the element name and value an instance of TM1py.Element
        {
            'US': instance of TM1py.Element,
            'CN': instance of TM1py.Element,
            'AU': instance of TM1py.Element
        }

        ElementAttributes of type TM1py.Objects.ElementAttribute

        Edges are represented as a TM1py.Utils.CaseAndSpaceInsensitiveTupleDict: 
        {
            (parent1, component1) : 10,
            (parent1, component2) : 30
        }

        Subsets is list of type TM1py.Subset

    """
    def __init__(self,
                 name,
                 dimension_name,
                 elements=None,
                 element_attributes=None,
                 edges=None,
                 subsets=None,
                 structure=None,
                 default_member=None):
        self._name = name
        self._dimension_name = dimension_name
        self._elements = CaseAndSpaceInsensitiveDict()
        if elements:
            for elem in elements:
                self._elements[elem.name] = elem
        self._element_attributes = element_attributes if element_attributes else []
        self._edges = edges if edges else CaseAndSpaceInsensitiveTuplesDict()
        self._subsets = subsets if subsets else []
        # balanced is true, false or None (in versions < TM1 11)
        self._balanced = structure if not structure else structure == 0
        self._default_member = default_member

    @classmethod
    def from_dict(cls, hierarchy_as_dict):
        # Build the Dictionary for the edges
        edges = CaseAndSpaceInsensitiveTuplesDict({
            (edge['ParentName'], edge['ComponentName']): edge['Weight']
            for edge in hierarchy_as_dict['Edges']
        })
        return cls(name=hierarchy_as_dict['Name'],
                   dimension_name=hierarchy_as_dict['UniqueName']
                   [1:hierarchy_as_dict['UniqueName'].find("].[")],
                   elements=[
                       Element.from_dict(elem)
                       for elem in hierarchy_as_dict['Elements']
                   ],
                   element_attributes=[
                       ElementAttribute(ea['Name'], ea['Type'])
                       for ea in hierarchy_as_dict['ElementAttributes']
                   ],
                   edges=edges,
                   subsets=[
                       subset['Name']
                       for subset in hierarchy_as_dict['Subsets']
                   ],
                   structure=hierarchy_as_dict['Structure']
                   if 'Structure' in hierarchy_as_dict else None,
                   default_member=hierarchy_as_dict['DefaultMember']['Name']
                   if hierarchy_as_dict['DefaultMember'] else None)

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def dimension_name(self):
        return self._dimension_name

    @property
    def elements(self):
        return self._elements

    @property
    def element_attributes(self):
        return self._element_attributes

    @property
    def edges(self):
        return self._edges

    @property
    def subsets(self):
        return self._subsets

    @property
    def balanced(self):
        return self._balanced

    @property
    def default_member(self):
        return self._default_member

    @property
    def body(self):
        return json.dumps(self._construct_body())

    @property
    def body_as_dict(self):
        return self._construct_body()

    def add_element(self, element_name, element_type):
        if element_name in self._elements:
            raise Exception("Elementname has to be unqiue")
        e = Element(name=element_name, element_type=element_type)
        self._elements[element_name] = e

    def update_element(self, element_name, element_type=None):
        self._elements[element_name].element_type = element_type

    def add_edge(self, parent, component, weight):
        self._edges[(parent, component)] = weight

    def update_edge(self, parent, component, weight):
        self._edges[(parent, component)] = weight

    def remove_edge(self, parent, component):
        if (parent, component) in self.edges:
            del self.edges[(parent, component)]

    def add_element_attribute(self, name, attribute_type):
        if name not in self.element_attributes:
            self.element_attributes.append(
                ElementAttribute(name, attribute_type))

    def remove_element_attribute(self, name):
        if name in self.element_attributes:
            self.element_attributes.remove(name)

    def _construct_body(self, element_attributes=False):
        """ 
        With TM1 10.2.2 Hierarchy and Element Attributes can't be created in one batch
        -> https://www.ibm.com/developerworks/community/forums/html/threadTopic?id=d91f3e0e-d305-44db-ac02-2fdcbee00393
        Thus, no need to have the ElementAttribute included in the JSON

        :param element_attributes: Only include element_attributes in body if explicitly asked for
        :return:
        """

        body_as_dict = collections.OrderedDict()
        body_as_dict['Name'] = self._name
        body_as_dict['Elements'] = []
        body_as_dict['Edges'] = []

        for element in self._elements.values():
            body_as_dict['Elements'].append(element.body_as_dict)
        for edge in self._edges:
            edge_as_dict = collections.OrderedDict()
            edge_as_dict['ParentName'] = edge[0]
            edge_as_dict['ComponentName'] = edge[1]
            edge_as_dict['Weight'] = self._edges[edge]
            body_as_dict['Edges'].append(edge_as_dict)
        if element_attributes:
            body_as_dict['ElementAttributes'] = [
                element_attribute.body_as_dict
                for element_attribute in self._element_attributes
            ]
        return body_as_dict

    def __iter__(self):
        return iter(self._elements.values())

    def __len__(self):
        return len(self._elements.values())
Exemplo n.º 11
0
 def test_eq_case_and_space_insensitive(self):
     _map = CaseAndSpaceInsensitiveDict()
     _map["key1"] = "value1"
     _map["KEY2"] = "value2"
     _map["K e Y 3"] = "value3"
     self.assertEqual(self.map, _map)
Exemplo n.º 12
0
 def test_eq(self):
     _map = CaseAndSpaceInsensitiveDict()
     _map["key1"] = "value1"
     _map["key2"] = "value2"
     _map["key3"] = "value3"
     self.assertEqual(self.map, _map)
Exemplo n.º 13
0
    def setUp(cls):

        cls.map = CaseAndSpaceInsensitiveDict()
        cls.map["key1"] = "value1"
        cls.map["key2"] = "value2"
        cls.map["key3"] = "value3"
Exemplo n.º 14
0
METHODS = CaseAndSpaceInsensitiveDict({
    "IRR": methods.irr,
    "NPV": methods.npv,
    "STDEV": methods.stdev,
    "STDEV_P": methods.stdev_p,
    "FV": methods.fv,
    "FV_SCHEDULE": methods.fv_schedule,
    "PV": methods.pv,
    "XNPV": methods.xnpv,
    "PMT": methods.pmt,
    "PPMT": methods.ppmt,
    "MIRR": methods.mirr,
    "XIRR": methods.xirr,
    "NPER": methods.nper,
    "RATE": methods.rate,
    "EFFECT": methods.effect,
    "NOMINAL": methods.nominal,
    "SLN": methods.sln,
    "MEAN": methods.mean,
    "SEM": methods.sem,
    "MEDIAN": methods.median,
    "MODE": methods.mode,
    "VAR": methods.var,
    "KURT": methods.kurt,
    "SKEW": methods.skew,
    "RNG": methods.rng,
    "MIN": methods.min_,
    "MAX": methods.max_,
    "SUM": methods.sum_,
    "COUNT": methods.count
})