cubewise-code / tm1py

TM1py is a Python package that wraps the TM1 REST API in a simple to use library.
http://tm1py.readthedocs.io/en/latest/
MIT License
192 stars 111 forks source link

Issue with copying view #541

Closed harveyca307 closed 3 years ago

harveyca307 commented 3 years ago

Describe what did you try to do with TM1py I am trying to copy a view and any named subsets from a Source server to a target server

Describe what's not working the way you expect Didn't get the expected result? Describe:

  1. I expected the view to get migrated to the target server
  2. The script is copying the subsets just fine and then bombing on the view create

Version

Additional context Script:

from TM1py.Services import TM1Service
from configparser import ConfigParser

config = ConfigParser()
config.read(r'config.ini')

source_tm1 = TM1Service(**config['glcs-test'], password='somepassword')
target_tm1 = TM1Service(**config['glcs'], password='somepassword')
cube = 'plan_BudgetPlan'
view = 'Chad'

def copy_subs(sub_dict: dict) -> str:
    for _object in sub_dict:
        dimension = _object
        subset = sub_dict[_object]
        source_sub = source_tm1.dimensions.subsets.get(dimension_name=dimension, hierarchy_name=dimension,
                                                       subset_name=subset, private=False)
        if target_tm1.dimensions.subsets.exists(dimension_name=dimension, hierarchy_name=dimension,
                                                subset_name=subset, private=False):
            target_tm1.dimensions.subsets.update(subset=source_sub, private=False)
        else:
            target_tm1.dimensions.subsets.create(subset=source_sub, private=False)
    return "Some string"

source_view = source_tm1.cubes.views.get(cube_name=cube, view_name=view, private=False)
dimensions = source_view.titles
dimensions.extend(source_view.rows)
dimensions.extend(source_view.columns)
sub_list = dict()
for dim in dimensions:
    if dim.subset.name:
        sub_list[dim.dimension_name] = dim.subset.name
if sub_list:
    copy_subs(sub_list)
if target_tm1.cubes.views.exists(cube_name=cube, view_name=view, private=False):
    target_tm1.cubes.views.update(view=source_view, private=False)
else:
    target_tm1.cubes.views.create(view=source_view, private=False)

Stack Trace:

Traceback (most recent call last):
  File "C:\Users\charvey\PycharmProjects\TM1_Promote\ztemp.py", line 40, in <module>
    target_tm1.cubes.views.create(view=source_view, private=False)
  File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\ViewService.py", line 35, in create
    return self._rest.POST(url, view.body, **kwargs)
  File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\RestService.py", line 77, in wrapper
    self.verify_response(response=response)
  File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\RestService.py", line 436, in verify_response
    raise TM1pyRestException(response.text,
TM1py.Exceptions.Exceptions.TM1pyRestException: Text: '{"error":{"code":"278","message":"Selected element was not specified on Title axis subset."}}' - Status Code: 400 - Reason: 'Bad Request' - Headers: {'Content-Length': '103', 'Connection': 'keep-alive', 'Content-Encoding': 'gzip', 'Cache-Control': 'no-cache', 'Content-Type': 'application/json; charset=utf-8', 'OData-Version': '4.0'}
macsir commented 3 years ago

Hi, @harveyca307 Could you verify all all subsets have been created successfully on the target server? Or some elements don't exist in some dimension on the target server which the soure view is using? Thanks.

harveyca307 commented 3 years ago

I verified that the dimensions are the same, and cube exists in both places. There is only one named subset for this test which is on the plan_Source dimension from PlanSamp

macsir commented 3 years ago
  1. Has that only subset been created sucessfully on that target? Is the source view using the subset?
  2. If yes, what if you just use the following the code to copy the view?
    source_view = source_tm1.cubes.views.get(cube_name=cube, view_name=view, private=False)
    target_tm1.cubes.views.create(view=source_view, private=False)
harveyca307 commented 3 years ago

The views.create is the line causing the problem

On Thu, May 13, 2021, 6:26 PM tm1sir @.***> wrote:

  1. Has that only subset been created sucessfully on that target? Is the source view using the subset?
  2. If yes, what if you just use the following the code to copy the view?

source_view = source_tm1.cubes.views.get(cube_name=cube, view_name=view, private=False)target_tm1.cubes.views.create(view=source_view, private=False)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cubewise-code/tm1py/issues/541#issuecomment-840891572, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOD7AY73PTTQIFPCH6TBIHTTNRN2DANCNFSM443LRSFQ .

MariusWirtz commented 3 years ago

In the Exception it says: Selected element was not specified on Title axis subset.

Could it be, that you are trying to migrate a view that has no selected element in a title? I guess the scenario could be that you have an existing view with an element like Product ABC and then later you delete Product ABC from the dimension. Then the view is kinda "broken" and it could be that the REST API wouldn't accept the approach to create a view that has this "broken" state.

harveyca307 commented 3 years ago

I checked this morning and there were no subsets with missing elements. I did only have one named subset being used in the view, so I created a named subset for every dimension. My thought was that maybe I was running up against a issue using default subsets. The subsets all get created just fine. The view create line seems to throw an error after running the function to create/update the subsets:

target_tm1.cubes.views.create(view=source_view, private=False)

The subsets are all public and have elements in them. The dimensions were copied to each instance from PlanSamp so they are identical. Next step is to debug until TM1py tries to execute the POST to create the view?

rclapp commented 3 years ago

Yes and see if you can catch the actual response from the TM1 server. This was likely covered in other replies but worth mentioning anyway. There are a number of things that worked in Native Views that break over the REST API

  1. Empty Subsets anywhere in the view
  2. Subsets with }RollUp Elements
  3. Views with No Context set
  4. Views with No Columns Set
  5. Subsets that contain Subsets as roll-ups (Edit->Insert Subset in perspectives aka UDC)

From: Chad Harvey @.> Reply-To: cubewise-code/tm1py @.> Date: Monday, May 17, 2021 at 9:20 AM To: cubewise-code/tm1py @.> Cc: Subscribed @.> Subject: Re: [cubewise-code/tm1py] Issue with copying view (#541)

I checked this morning and there were no subsets with missing elements. I did only have one named subset being used in the view, so I created a named subset for every dimension. My thought was that maybe I was running up against a issue using default subsets. The subsets all get created just fine. The view create line seems to throw an error after running the function to create/update the subsets:

target_tm1.cubes.views.create(view=source_view, private=False)

The subsets are all public and have elements in them. The dimensions were copied to each instance from PlanSamp so they are identical. Next step is to debug until TM1py tries to execute the POST to create the view?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/cubewise-code/tm1py/issues/541#issuecomment-842457325, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AEK7GZQXUEMDIBEWK5GUMATTOE62NANCNFSM443LRSFQ.

harveyca307 commented 3 years ago

Source view: image

JSON: image

Stack Trace: image

rclapp commented 3 years ago

The error says you don't have anything selected on titles. This is likely due to the fact that views created in perspectives are not always Rest compatible.

Sent from my mobile phone

On May 18, 2021 4:01 PM, Chad Harvey @.***> wrote:

Source view: [image]https://user-images.githubusercontent.com/59240547/118733851-c33e0880-b802-11eb-9a45-e12e62a3df51.png

JSON: [image]https://user-images.githubusercontent.com/59240547/118733898-da7cf600-b802-11eb-9c47-e5b59d337840.png

Stack Trace: [image]https://user-images.githubusercontent.com/59240547/118733938-ea94d580-b802-11eb-8fdd-2af27cd90731.png

- You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/cubewise-code/tm1py/issues/541#issuecomment-843621916, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AEK7GZT5F6Y475OJA2QBT63TOLWSNANCNFSM443LRSFQ.

MariusWirtz commented 3 years ago

A screenshot of the opened view in architect would be interesting

harveyca307 commented 3 years ago

Architect View Screenshot: image

PAW Created view: image

Different Stack Trace for PAW View:

C:\Users\charvey\PycharmProjects\TM1_Promote\venv\Scripts\python.exe C:/Users/charvey/PycharmProjects/TM1_Promote/ztemp.py
Traceback (most recent call last):
  File "C:\Users\charvey\PycharmProjects\TM1_Promote\ztemp.py", line 28, in <module>
    dimensions = source_view._titles
AttributeError: 'MDXView' object has no attribute '_titles'

Process finished with exit code 1
MariusWirtz commented 3 years ago

The view created from PAW is an MDXView. It needs to be treated differently. This explains the error in your last post. The MDXView doesn't have rows, columns, titles properties like the NativeView does

Based on the screenshot from Architect, I can't see what's wrong with the view setup. I think it's either, something unsupported in the REST API like @rclapp already pointed out or the selected element doesn't exist in the target instance.

harveyca307 commented 3 years ago

In looking at the Debug window, I am seeing something that looks odd: image

Dimensions 5 and 6 are Row and Column dimensions in the Native view (opened plan_BudgetPlan, hit save view). Could this be causing my issue where it thinks that my dimension is on the Row and Title space?

Grabbed the source view by:


source_view = source_tm1.cubes.views.get(cube_name=cube, view_name=view, private=False)
MariusWirtz commented 3 years ago

Something must be wrong with the view. Can you please post the JSON definition of the view here?

from TM1py import TM1Service

with TM1Service(address='localhost', port=12354, ssl=True, user="admin", password="apple") as tm1:
    view = tm1.views.get("c1", "v1", private=False)

    print(str(view))
harveyca307 commented 3 years ago

Below is the output of

print(str(source_view))
{"@odata.type": "ibm.tm1.api.v1.NativeView","Name": "Chad","Columns":[{"Subset": {"Hierarchy@odata.bind": "Dimensions('plan_time')/Hierarchies('plan_time')", "Elements@odata.bind": ["Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Description')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jan-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Feb-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Mar-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Apr-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('May-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jun-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jul-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Aug-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Sep-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Oct-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Nov-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Dec-2003')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jan-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Feb-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Mar-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Apr-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('May-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jun-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jul-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Aug-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Sep-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Oct-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Nov-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Dec-2004')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jan-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Feb-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Mar-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Apr-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('May-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jun-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Jul-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Aug-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Sep-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Oct-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Nov-2005')", "Dimensions('plan_time')/Hierarchies('plan_time')/Elements('Dec-2005')"]}}],"Rows":[{"Subset@odata.bind": "Dimensions('plan_source')/Hierarchies('plan_source')/Subsets('Chad')"}],"Titles":[{"Subset": {"Hierarchy@odata.bind": "Dimensions('plan_version')/Hierarchies('plan_version')", "Elements@odata.bind": ["Dimensions('plan_version')/Hierarchies('plan_version')/Elements('FY 2003 Budget')", "Dimensions('plan_version')/Hierarchies('plan_version')/Elements('FY 2004 Budget')", "Dimensions('plan_version')/Hierarchies('plan_version')/Elements('FY 2004 Forecast')", "Dimensions('plan_version')/Hierarchies('plan_version')/Elements('FY 2005 Budget-baseline')", "Dimensions('plan_version')/Hierarchies('plan_version')/Elements('FY 2005 Budget-upside')"]}, "Selected@odata.bind": "Dimensions('plan_version')/Hierarchies('plan_version')/Elements('FY 2003 Budget')"},{"Subset": {"Hierarchy@odata.bind": "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')", "Elements@odata.bind": ["Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Elements('10000')", "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Elements('10100')", "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Elements('10200')", "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Elements('10300')", "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Elements('10400')"]}, "Selected@odata.bind": "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Elements('10000')"},{"Subset": {"Hierarchy@odata.bind": "Dimensions('plan_department')/Hierarchies('plan_department')", "Elements@odata.bind": ["Dimensions('plan_department')/Hierarchies('plan_department')/Elements('1000')", "Dimensions('plan_department')/Hierarchies('plan_department')/Elements('100')", "Dimensions('plan_department')/Hierarchies('plan_department')/Elements('200')", "Dimensions('plan_department')/Hierarchies('plan_department')/Elements('300')", "Dimensions('plan_department')/Hierarchies('plan_department')/Elements('400')"]}, "Selected@odata.bind": "Dimensions('plan_department')/Hierarchies('plan_department')/Elements('1000')"},{"Subset": {"Hierarchy@odata.bind": "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')", "Elements@odata.bind": ["Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/Elements('Net Operating Income')", "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/Elements('Revenue')", "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/Elements('COS')", "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/Elements('Operating Expense')"]}, "Selected@odata.bind": "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/Elements('Net Operating Income')"},{"Subset": {"Hierarchy@odata.bind": "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')", "Elements@odata.bind": ["Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('local')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('beginning')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('ending')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('planning')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('spot')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('actual')"]}, "Selected@odata.bind": "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('local')"}],"SuppressEmptyColumns": false,"SuppressEmptyRows":false,"FormatString": "0.#########"}
MariusWirtz commented 3 years ago

I can't reproduce the issue. When I post the JSON against my local Planning Sample model, it fails with:

{
    "error": {
        "code": "278",
        "message": "'Description' can not be found in collection of type 'Element'."
    }
}

After I created the element Description in the plan_time dimension it failed with:

{
    "error": {
        "code": "278",
        "message": "'Chad' can not be found in collection of type 'Subset'."
    }
}

After I created the Chad subset, the view was created successfully.

It must be related to your version or setup. Please post the latest error and stack trace again.

harveyca307 commented 3 years ago

Stack Trace:

C:\Users\charvey\PycharmProjects\TM1_Promote\venv\Scripts\python.exe C:/Users/charvey/PycharmProjects/TM1_Promote/ztemp.py Traceback (most recent call last): File "C:\Users\charvey\PycharmProjects\TM1_Promote\ztemp.py", line 41, in target_tm1.cubes.views.create(source_view, private=False) File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\ViewService.py", line 35, in create return self._rest.POST(url, view.body, **kwargs) File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\RestService.py", line 77, in wrapper self.verify_response(response=response) File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\RestService.py", line 436, in verify_response raise TM1pyRestException(response.text, TM1py.Exceptions.Exceptions.TM1pyRestException: Text: '{"error":{"code":"278","message":"'Default' can not be found in collection of type 'Subset'."}}' - Status Code: 404 - Reason: 'Not Found' - Headers: {'Content-Length': '107 ', 'Connection': 'keep-alive', 'Content-Encoding': 'gzip', 'Cache-Control': 'no-cache', 'Content-Type': 'application/json; charset=utf-8', 'OData-Version': '4.0'}

Process finished with exit code 1

View JSON:

{"@odata.type": "ibm.tm1.api.v1.NativeView","Name": "Chad","Columns":[{"Subset@odata.bind": "Dimensions('plan_time')/Hierarchies('plan_time')/Subsets('Default')"}],"Rows":[{"Subset@odata.bind": "Dimensions('plan_source')/Hierar
chies('plan_source')/Subsets('Chad')"}],"Titles":[{"Subset@odata.bind": "Dimensions('plan_version')/Hierarchies('plan_version')/Subsets('Default')", "Selected@odata.bind": "Dimensions('plan_version')/Hierarchies('plan_version')
/Elements('FY 2003 Budget')"},{"Subset@odata.bind": "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Subsets('Default')", "Selected@odata.bind": "Dimensions('plan_business_unit')/Hierarchies('plan_business_un
it')/Elements('10000')"},{"Subset@odata.bind": "Dimensions('plan_department')/Hierarchies('plan_department')/Subsets('Default')", "Selected@odata.bind": "Dimensions('plan_department')/Hierarchies('plan_department')/Elements('10
00')"},{"Subset@odata.bind": "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/Subsets('Default')", "Selected@odata.bind": "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/El
ements('Revenue')"},{"Subset": {"Hierarchy@odata.bind": "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')", "Elements@odata.bind": ["Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Eleme
nts('local')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('beginning')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('ending')", "Dimensions('plan_exchange_
rates')/Hierarchies('plan_exchange_rates')/Elements('planning')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('spot')", "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/El
ements('actual')"]}, "Selected@odata.bind": "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Elements('local')"}],"SuppressEmptyColumns": false,"SuppressEmptyRows":false,"FormatString": "0.#########"}
MariusWirtz commented 3 years ago

You are missing a subset called Default in one of the dimensions

harveyca307 commented 3 years ago

Sorry had some code commented out. I also recreated view in Architect so that each dimension had a static named subset that was not the Default subset. Running PA Local 2.0.9.8 and PAW Local 2.0.63.

Stack trace:

C:\Users\charvey\PycharmProjects\TM1_Promote\venv\Scripts\python.exe C:/Users/charvey/PycharmProjects/TM1_Promote/ztemp.py Traceback (most recent call last): File "C:\Users\charvey\PycharmProjects\TM1_Promote\ztemp.py", line 41, in target_tm1.cubes.views.create(source_view, private=False) File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\ViewService.py", line 35, in create return self._rest.POST(url, view.body, **kwargs) File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\RestService.py", line 77, in wrapper self.verify_response(response=response) File "C:\Users\charvey\PycharmProjects\TM1_Promote\venv\lib\site-packages\TM1py\Services\RestService.py", line 436, in verify_response raise TM1pyRestException(response.text, TM1py.Exceptions.Exceptions.TM1pyRestException: Text: '{"error":{"code":"278","message":"Selected element was not specified on Title axis subset."}}' - Status Code: 400 - Reason: 'Bad Request' - Headers: {'Content-Length': '103 ', 'Connection': 'keep-alive', 'Content-Encoding': 'gzip', 'Cache-Control': 'no-cache', 'Content-Type': 'application/json; charset=utf-8', 'OData-Version': '4.0'}

Process finished with exit code 1

Cube View JSON:

{"@odata.type": "ibm.tm1.api.v1.NativeView","Name": "Chad","Columns":[{"Subset@odata.bind": "Dimensions('plan_time')/Hierarchies('plan_time')/Subsets('Subset1')"}],"Rows":[{"Subset@odata.bind": "Dimensions('plan_source')/Hierar
chies('plan_source')/Subsets('Subset1')"}],"Titles":[{"Subset@odata.bind": "Dimensions('plan_version')/Hierarchies('plan_version')/Subsets('Subset1')", "Selected@odata.bind": "Dimensions('plan_version')/Hierarchies('plan_versio
n')/Elements('FY 2003 Budget')"},{"Subset@odata.bind": "Dimensions('plan_business_unit')/Hierarchies('plan_business_unit')/Subsets('Subset1')", "Selected@odata.bind": "Dimensions('plan_business_unit')/Hierarchies('plan_business
_unit')/Elements('10000')"},{"Subset@odata.bind": "Dimensions('plan_department')/Hierarchies('plan_department')/Subsets('Subset1')", "Selected@odata.bind": "Dimensions('plan_department')/Hierarchies('plan_department')/Elements(
'1000')"},{"Subset@odata.bind": "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')/Subsets('Subset1')", "Selected@odata.bind": "Dimensions('plan_chart_of_accounts')/Hierarchies('plan_chart_of_accounts')
/Elements('Revenue')"},{"Subset@odata.bind": "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates')/Subsets('Subset1')", "Selected@odata.bind": "Dimensions('plan_exchange_rates')/Hierarchies('plan_exchange_rates'
)/Elements('local')"}],"SuppressEmptyColumns": false,"SuppressEmptyRows":false,"FormatString": "0.#########"}

Script code:

from TM1py.Services import TM1Service
from configparser import ConfigParser
config = ConfigParser()
config.read(r'config.ini')

source_tm1 = TM1Service(**config['psamp'], password='somepass')
target_tm1 = TM1Service(**config['glcs'], password='somepass')
cube = 'plan_BudgetPlan'
view = 'Chad'

def copy_subs(sub_dict: dict) -> str:
    for _object in sub_dict:
        dimension = _object
        subset = sub_dict[_object]
        source_sub = source_tm1.dimensions.subsets.get(dimension_name=dimension, hierarchy_name=dimension,
                                                       subset_name=subset, private=False)
        if target_tm1.dimensions.subsets.exists(dimension_name=dimension, hierarchy_name=dimension,
                                                subset_name=subset, private=False):
            target_tm1.dimensions.subsets.update(subset=source_sub, private=False)
        else:
            target_tm1.dimensions.subsets.create(subset=source_sub, private=False)
    return "Some string"

source_view = source_tm1.cubes.views.get(cube_name=cube, view_name=view, private=False)
# print(str(source_view))
dimensions = source_view._titles
dimensions.extend(source_view.rows)
dimensions.extend(source_view.columns)
sub_list = dict()
for dim in dimensions:
    if dim.subset.name:
        sub_list[dim.dimension_name] = dim.subset.name
if sub_list:
    copy_subs(sub_list)
if target_tm1.cubes.views.exists(cube_name=cube, view_name=view, private=False):
    target_tm1.cubes.views.update(view=source_view, private=False)
else:
    target_tm1.cubes.views.create(source_view, private=False)

Target Cube before running script: image

Source View in Architect: image

Target Cube after script: image

It created the subsets, but failed on the View create. Each subset has one element and is static.

harveyca307 commented 3 years ago

Did some more digging. If I run the 2 processes separately (Copy_Subs, then Copy View in 2 separate runs) it works. Talking to a colleague it seems that there might be a need to disconnect and reconnect to the API after creating/updating the Subsets. Testing that now...

MariusWirtz commented 3 years ago

OK. It could well be that TM1 needs some digesting time between certain operations. I have seen this before. Perhaps sleeping for a second or two, between creating the subsets and creating the views would be enough.

harveyca307 commented 3 years ago

Added a sleep for anywhere from 10-30 seconds with no success. I am hearing that a possible logout and reconnect is necessary. So I am thinking a tm1.logout followed by a new connection request? tm1 = TM1Service(.....?

MariusWirtz commented 3 years ago

@harveyca307,

since you have a reproducible case it's best to report this directly to IBM. I think that's a bug within TM1.

tmonty12 commented 3 years ago

The issue isn't with the REST API, it has to do with those two ViewAxisSelection objects that are being added into the view.titles list. This happens in your code when you do this:

dimensions = source_view.titles
dimensions.extend(source_view.rows)
dimensions.extend(source_view.columns)

The dimensions variable is just a reference to the source_view.titles so when you extend the list with the source_view.rows and source_view.columns, those ViewAxisSelection objects are being added to the source_view.titles list. When you use the view.create() function and it creates the url for the api, the ViewAxisSelection objects are appended to the title area but since they have no selected element you get the "Selected element was not specified on Title axis subset" error when the request is sent.

To fix this error just make sure you create a new list in memory so that you aren't mutating the source_view object.

MariusWirtz commented 3 years ago

Thanks @tmonty12.

@harveyca307 Please change the code to dimensions = list(source_view.titles) and let us know how it goes.