Skip to content

ApplicationService

ApplicationService(tm1_rest)

Bases: ObjectService

Service to Read and Write TM1 Applications

Parameters:

Name Type Description Default
tm1_rest RestService
required
Source code in TM1py/Services/ApplicationService.py
def __init__(self, tm1_rest: RestService):
    """

    :param tm1_rest:
    """
    super().__init__(tm1_rest)
    self._rest = tm1_rest
    self._private_path_cache: Dict[str, int] = {}

create(application, private=False, use_cache=False, **kwargs)

Create Planning Analytics application

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
application Union[Application, DocumentApplication]

instance of Application

required
private bool

boolean

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Response
Source code in TM1py/Services/ApplicationService.py
def create(self, application: Union[Application, DocumentApplication], private: bool = False,
           use_cache: bool = False, **kwargs) -> Response:
    """Create Planning Analytics application

    Automatically handles mixed public/private folder hierarchies.

    :param application: instance of Application
    :param private: boolean
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    base_url, in_private_context = self._resolve_path(application.path, private, use_cache, **kwargs)

    # Use PrivateContents if we're in a private context OR if private=True
    contents = "PrivateContents" if (private or in_private_context) else "Contents"
    url = base_url + "/" + contents

    response = self._rest.POST(url, application.body, **kwargs)

    if application.application_type == ApplicationTypes.DOCUMENT:
        url = format_url(
            base_url + "/" + contents + "('{name}{suffix}')/Document/Content",
            name=application.name,
            suffix=".blob" if not verify_version(required_version="12", version=self.version) else "",
        )
        response = self._rest.PUT(url, application.content, headers=self.binary_http_header, **kwargs)

    return response

create_document_from_file(path_to_file, application_path, application_name, private=False, use_cache=False, **kwargs)

Create DocumentApplication in TM1 from local file

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path_to_file str
required
application_path str
required
application_name str
required
private bool
False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Response
Source code in TM1py/Services/ApplicationService.py
def create_document_from_file(
    self, path_to_file: str, application_path: str, application_name: str, private: bool = False,
    use_cache: bool = False, **kwargs
) -> Response:
    """Create DocumentApplication in TM1 from local file

    Automatically handles mixed public/private folder hierarchies.

    :param path_to_file:
    :param application_path:
    :param application_name:
    :param private:
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    with open(path_to_file, "rb") as file:
        application = DocumentApplication(path=application_path, name=application_name, content=file.read())
        return self.create(application=application, private=private, use_cache=use_cache, **kwargs)

delete(path, application_type, application_name, private=False, use_cache=False, **kwargs)

Delete Planning Analytics application reference

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path str

path through folder structure to delete the applications entry. For instance: "Finance/Reports"

required
application_type Union[str, ApplicationTypes]

type of the to be deleted application entry

required
application_name str

name of the to be deleted application entry

required
private bool

Access level of the to be deleted object

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Response
Source code in TM1py/Services/ApplicationService.py
def delete(
    self,
    path: str,
    application_type: Union[str, ApplicationTypes],
    application_name: str,
    private: bool = False,
    use_cache: bool = False,
    **kwargs,
) -> Response:
    """Delete Planning Analytics application reference

    Automatically handles mixed public/private folder hierarchies.

    :param path: path through folder structure to delete the applications entry. For instance: "Finance/Reports"
    :param application_type: type of the to be deleted application entry
    :param application_name: name of the to be deleted application entry
    :param private: Access level of the to be deleted object
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    # raise ValueError if not a valid ApplicationType
    application_type = ApplicationTypes(application_type)

    if not application_type == ApplicationTypes.FOLDER and not verify_version(
        required_version="12", version=self.version
    ):
        application_name += application_type.suffix

    base_url, in_private_context = self._resolve_path(path, private, use_cache, **kwargs)

    # Use PrivateContents if we're in a private context OR if private=True
    contents = "PrivateContents" if (private or in_private_context) else "Contents"
    url = format_url(base_url + "/" + contents + "('{}')", application_name)

    return self._rest.DELETE(url, **kwargs)

discover(path='', include_private=False, recursive=False, flat=False, **kwargs)

Discover applications in the Applications folder.

Traverses the application hierarchy and returns information about all discovered items including folders, documents, views, and other references.

Parameters:

Name Type Description Default
path str

starting path (empty string = root 'Applications' folder)

''
include_private bool

whether to include private assets in the results

False
recursive bool

whether to recurse into subfolders

False
flat bool

if True, returns a flat list; if False (default), returns nested structure

False

Returns:

Type Description
List[Dict]

list of dictionaries with keys: @odata.type, type, id, name, path, is_private - @odata.type: full OData type (e.g., '#ibm.tm1.api.v1.Folder') - type: simplified type name (e.g., 'Folder') For nested mode, folders also have a 'children' key when recursive=True

Source code in TM1py/Services/ApplicationService.py
def discover(
    self,
    path: str = "",
    include_private: bool = False,
    recursive: bool = False,
    flat: bool = False,
    **kwargs
) -> List[Dict]:
    """Discover applications in the Applications folder.

    Traverses the application hierarchy and returns information about all
    discovered items including folders, documents, views, and other references.

    :param path: starting path (empty string = root 'Applications' folder)
    :param include_private: whether to include private assets in the results
    :param recursive: whether to recurse into subfolders
    :param flat: if True, returns a flat list; if False (default), returns nested structure
    :return: list of dictionaries with keys: @odata.type, type, id, name, path, is_private
             - @odata.type: full OData type (e.g., '#ibm.tm1.api.v1.Folder')
             - type: simplified type name (e.g., 'Folder')
             For nested mode, folders also have a 'children' key when recursive=True
    """
    results = []  # Accumulator for flat mode

    # Determine if we're starting in a private context (path contains private folders)
    in_private_context = False
    if path.strip() and include_private:
        _, in_private_context = self._resolve_path(path, private=True, use_cache=False, **kwargs)

    # Use the unified discovery method
    items = self._discover_at_path(
        path=path,
        include_private=include_private,
        recursive=recursive,
        flat=flat,
        in_private_context=in_private_context,
        results=results,
        **kwargs
    )

    return results if flat else items

exists(path, application_type, name, private=False, use_cache=False, **kwargs)

Check if application exists

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path str
required
application_type Union[str, ApplicationTypes]
required
name str
required
private bool
False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
bool
Source code in TM1py/Services/ApplicationService.py
def exists(
    self, path: str, application_type: Union[str, ApplicationTypes], name: str, private: bool = False,
    use_cache: bool = False, **kwargs
) -> bool:
    """Check if application exists

    Automatically handles mixed public/private folder hierarchies.

    :param path:
    :param application_type:
    :param name:
    :param private:
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    # raise ValueError if not a valid ApplicationType
    application_type = ApplicationTypes(application_type)

    if not application_type == ApplicationTypes.FOLDER and not verify_version(
        required_version="12", version=self.version
    ):
        name += application_type.suffix

    # For exists check with private=True, we need special handling
    # because we want to check both public and private paths
    if not private:
        # Simple public check
        segments = path.split("/") if path.strip() else []
        mid = self._build_path_url(segments, None)
        url = "/Contents('Applications')" + mid + "/Contents('" + name + "')"
        return self._exists(url, **kwargs)

    # For private access, first try to resolve the path
    segments = path.split("/") if path.strip() else []

    if not segments:
        # Root level - just check directly
        url = "/Contents('Applications')/PrivateContents('" + name + "')"
        return self._exists(url, **kwargs)

    # Check cache first
    cache_key = "/".join(segments)
    if use_cache and cache_key in self._private_path_cache:
        boundary = self._private_path_cache[cache_key]
        mid = self._build_path_url(segments, boundary)
        in_private_context = boundary < len(segments)
        contents = "PrivateContents" if in_private_context else "Contents"
        url = "/Contents('Applications')" + mid + "/" + contents + "('" + name + "')"
        return self._exists(url, **kwargs)

    # Try all-public path first
    mid_public = self._build_path_url(segments, None)
    url_public = "/Contents('Applications')" + mid_public + "/PrivateContents('" + name + "')"
    if self._exists(url_public, **kwargs):
        if use_cache:
            self._private_path_cache[cache_key] = len(segments)
        return True

    # Try to find the private boundary
    boundary = self._find_private_boundary(segments, **kwargs)

    if boundary == -1:
        return False  # Path doesn't exist

    if use_cache:
        self._private_path_cache[cache_key] = boundary

    mid = self._build_path_url(segments, boundary)
    # If path has private folders, item must be accessed via PrivateContents
    contents = "PrivateContents" if boundary < len(segments) else "PrivateContents"
    url = "/Contents('Applications')" + mid + "/" + contents + "('" + name + "')"
    return self._exists(url, **kwargs)

get(path, application_type, name, private=False, use_cache=False, **kwargs)

Retrieve Planning Analytics Application

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path str

path with forward slashes

required
application_type Union[str, ApplicationTypes]

str or ApplicationType from Enum

required
name str
required
private bool
False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Application
Source code in TM1py/Services/ApplicationService.py
def get(
    self, path: str, application_type: Union[str, ApplicationTypes], name: str, private: bool = False,
    use_cache: bool = False, **kwargs
) -> Application:
    """Retrieve Planning Analytics Application

    Automatically handles mixed public/private folder hierarchies.

    :param path: path with forward slashes
    :param application_type: str or ApplicationType from Enum
    :param name:
    :param private:
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    # raise ValueError if not a valid ApplicationType
    application_type = ApplicationTypes(application_type)

    # documents require special treatment
    if application_type == ApplicationTypes.DOCUMENT:
        return self.get_document(path=path, name=name, private=private, use_cache=use_cache, **kwargs)

    if not application_type == ApplicationTypes.FOLDER and not verify_version(
        required_version="12", version=self.version
    ):
        name += application_type.suffix

    base_url, in_private_context = self._resolve_path(path, private, use_cache, **kwargs)

    # Use PrivateContents if we're in a private context OR if private=True
    contents = "PrivateContents" if (private or in_private_context) else "Contents"
    base_url = format_url(base_url + "/" + contents + "('{}')", name)

    if application_type == ApplicationTypes.CUBE:
        response = self._rest.GET(url=base_url + "?$expand=Cube($select=Name)", **kwargs)
        return CubeApplication(path=path, name=name, cube_name=response.json()["Cube"]["Name"])

    elif application_type == ApplicationTypes.CHORE:
        response = self._rest.GET(url=base_url + "?$expand=Chore($select=Name)", **kwargs)
        return ChoreApplication(path=path, name=name, chore_name=response.json()["Chore"]["Name"])

    elif application_type == ApplicationTypes.DIMENSION:
        response = self._rest.GET(url=base_url + "?$expand=Dimension($select=Name)", **kwargs)
        return DimensionApplication(path=path, name=name, dimension_name=response.json()["Dimension"]["Name"])

    elif application_type == ApplicationTypes.FOLDER:
        # implicit TM1pyException if application doesn't exist
        self._rest.GET(url=base_url, **kwargs)
        return FolderApplication(path=path, name=name)

    elif application_type == ApplicationTypes.LINK:
        # implicit TM1pyException if application doesn't exist
        self._rest.GET(url=base_url, **kwargs)
        response = self._rest.GET(base_url + "?$expand=*", **kwargs)
        return LinkApplication(path=path, name=name, url=response.json()["URL"])

    elif application_type == ApplicationTypes.PROCESS:
        response = self._rest.GET(url=base_url + "?$expand=Process($select=Name)", **kwargs)
        return ProcessApplication(path=path, name=name, process_name=response.json()["Process"]["Name"])

    elif application_type == ApplicationTypes.SUBSET:
        url = "".join(
            [
                base_url,
                "?$expand=Subset($select=Name;$expand=Hierarchy($select=Name;$expand=Dimension($select=Name)))",
            ]
        )
        response = self._rest.GET(url=url, **kwargs)
        return SubsetApplication(
            path=path,
            name=name,
            dimension_name=response.json()["Subset"]["Hierarchy"]["Dimension"]["Name"],
            hierarchy_name=response.json()["Subset"]["Hierarchy"]["Name"],
            subset_name=response.json()["Subset"]["Name"],
        )

    elif application_type == ApplicationTypes.VIEW:
        response = self._rest.GET(url=base_url + "?$expand=View($select=Name;$expand=Cube($select=Name))", **kwargs)
        return ViewApplication(
            path=path,
            name=name,
            cube_name=response.json()["View"]["Cube"]["Name"],
            view_name=response.json()["View"]["Name"],
        )

get_all_private_root_names(**kwargs)

Retrieve all private root application names.

Parameters:

Name Type Description Default
kwargs

Additional arguments for the REST request.

{}

Returns:

Type Description

List of private root application names.

Source code in TM1py/Services/ApplicationService.py
def get_all_private_root_names(self, **kwargs):
    """
    Retrieve all private root application names.

    :param kwargs: Additional arguments for the REST request.
    :return: List of private root application names.
    """
    url = "/Contents('Applications')/PrivateContents"
    response = self._rest.GET(url, **kwargs)
    applications = list(application["Name"] for application in response.json()["value"])
    return applications

get_all_public_root_names(**kwargs)

Retrieve all public root application names.

Parameters:

Name Type Description Default
kwargs

Additional arguments for the REST request.

{}

Returns:

Type Description

List of public root application names.

Source code in TM1py/Services/ApplicationService.py
def get_all_public_root_names(self, **kwargs):
    """
    Retrieve all public root application names.

    :param kwargs: Additional arguments for the REST request.
    :return: List of public root application names.
    """
    url = "/Contents('Applications')/Contents"
    response = self._rest.GET(url, **kwargs)
    applications = list(application["Name"] for application in response.json()["value"])
    return applications

get_document(path, name, private=False, use_cache=False, **kwargs)

Get Excel Application from TM1 Server in binary format. Can be dumped to file.

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path str

path through folder structure to application. For instance: "Finance/P&L.xlsx"

required
name str

name of the application

required
private bool

boolean

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
DocumentApplication

Return DocumentApplication

Source code in TM1py/Services/ApplicationService.py
def get_document(self, path: str, name: str, private: bool = False, use_cache: bool = False,
                 **kwargs) -> DocumentApplication:
    """Get Excel Application from TM1 Server in binary format. Can be dumped to file.

    Automatically handles mixed public/private folder hierarchies.

    :param path: path through folder structure to application. For instance: "Finance/P&L.xlsx"
    :param name: name of the application
    :param private: boolean
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return: Return DocumentApplication
    """
    if not name.endswith(ApplicationTypes.DOCUMENT.suffix) and not verify_version(
        required_version="12", version=self.version
    ):
        name += ApplicationTypes.DOCUMENT.suffix

    base_url, in_private_context = self._resolve_path(path, private, use_cache, **kwargs)

    # Use PrivateContents if we're in a private context OR if private=True
    contents = "PrivateContents" if (private or in_private_context) else "Contents"

    url = format_url(base_url + "/" + contents + "('{}')/Document/Content", name)
    content = self._rest.GET(url, **kwargs).content

    url = format_url(base_url + "/" + contents + "('{}')/Document", name)
    document_fields = self._rest.GET(url, **kwargs).json()

    return DocumentApplication(
        path=path,
        name=name,
        content=content,
        file_id=document_fields.get("ID"),
        file_name=document_fields.get("Name"),
        last_updated=document_fields.get("LastUpdated"),
    )

get_names(path, private=False, use_cache=False, **kwargs)

Retrieve Planning Analytics Application names in given path

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path str

path with forward slashes

required
private bool

boolean - whether to retrieve private or public contents at the leaf

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description

list of application names

Source code in TM1py/Services/ApplicationService.py
def get_names(self, path: str, private: bool = False, use_cache: bool = False, **kwargs):
    """Retrieve Planning Analytics Application names in given path

    Automatically handles mixed public/private folder hierarchies.

    :param path: path with forward slashes
    :param private: boolean - whether to retrieve private or public contents at the leaf
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return: list of application names
    """
    base_url, in_private_context = self._resolve_path(path, private, use_cache, **kwargs)

    # Use PrivateContents if we're in a private context OR if private=True
    contents = "PrivateContents" if (private or in_private_context) else "Contents"
    url = base_url + "/" + contents

    response = self._rest.GET(url=url, **kwargs)
    return [application["Name"] for application in response.json()["value"]]

rename(path, application_type, application_name, new_application_name, private=False, use_cache=False, **kwargs)

Rename a Planning Analytics application.

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path str

path through folder structure

required
application_type Union[str, ApplicationTypes]

type of the application

required
application_name str

current name of the application

required
new_application_name str

new name for the application

required
private bool

Access level of the object

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Source code in TM1py/Services/ApplicationService.py
def rename(
    self,
    path: str,
    application_type: Union[str, ApplicationTypes],
    application_name: str,
    new_application_name: str,
    private: bool = False,
    use_cache: bool = False,
    **kwargs,
):
    """Rename a Planning Analytics application.

    Automatically handles mixed public/private folder hierarchies.

    :param path: path through folder structure
    :param application_type: type of the application
    :param application_name: current name of the application
    :param new_application_name: new name for the application
    :param private: Access level of the object
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    # raise ValueError if not a valid ApplicationType
    application_type = ApplicationTypes(application_type)

    if not application_type == ApplicationTypes.FOLDER and not verify_version(
        required_version="12", version=self.version
    ):
        application_name += application_type.suffix

    base_url, in_private_context = self._resolve_path(path, private, use_cache, **kwargs)

    # Use PrivateContents if we're in a private context OR if private=True
    contents = "PrivateContents" if (private or in_private_context) else "Contents"
    url = format_url(base_url + "/" + contents + "('{}')/tm1.Move", application_name)

    data = {"Name": new_application_name}
    return self._rest.POST(url, data=json.dumps(data), **kwargs)

update(application, private=False, use_cache=False, **kwargs)

Update Planning Analytics application

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
application Union[Application, DocumentApplication]

instance of Application

required
private bool

boolean

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Response
Source code in TM1py/Services/ApplicationService.py
def update(self, application: Union[Application, DocumentApplication], private: bool = False,
           use_cache: bool = False, **kwargs) -> Response:
    """Update Planning Analytics application

    Automatically handles mixed public/private folder hierarchies.

    :param application: instance of Application
    :param private: boolean
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    base_url, in_private_context = self._resolve_path(application.path, private, use_cache, **kwargs)

    # Use PrivateContents if we're in a private context OR if private=True
    contents = "PrivateContents" if (private or in_private_context) else "Contents"

    if application.application_type == ApplicationTypes.DOCUMENT:
        url = format_url(
            base_url + "/" + contents + "('{name}{extension}')/Document/Content",
            name=application.name,
            extension="" if verify_version("12", self.version) else ".blob"
        )
        response = self._rest.PATCH(url=url, data=application.content, headers=self.binary_http_header, **kwargs)
    else:
        url = base_url + "/" + contents
        response = self._rest.POST(url, application.body, **kwargs)

    return response

update_document_from_file(path_to_file, application_path, application_name, private=False, use_cache=False, **kwargs)

Update DocumentApplication in TM1 from local file

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path_to_file str
required
application_path str
required
application_name str
required
private bool
False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Response
Source code in TM1py/Services/ApplicationService.py
def update_document_from_file(
    self, path_to_file: str, application_path: str, application_name: str, private: bool = False,
    use_cache: bool = False, **kwargs
) -> Response:
    """Update DocumentApplication in TM1 from local file

    Automatically handles mixed public/private folder hierarchies.

    :param path_to_file:
    :param application_path:
    :param application_name:
    :param private:
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return:
    """
    with open(path_to_file, "rb") as file:
        application = DocumentApplication(path=application_path, name=application_name, content=file.read())
        return self.update(application=application, private=private, use_cache=use_cache, **kwargs)

update_or_create(application, private=False, use_cache=False, **kwargs)

Update or create Planning Analytics application

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
application Union[Application, DocumentApplication]

instance of Application

required
private bool

boolean

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Response

Response

Source code in TM1py/Services/ApplicationService.py
def update_or_create(
    self, application: Union[Application, DocumentApplication], private: bool = False,
    use_cache: bool = False, **kwargs
) -> Response:
    """Update or create Planning Analytics application

    Automatically handles mixed public/private folder hierarchies.

    :param application: instance of Application
    :param private: boolean
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return: Response
    """
    if self.exists(
        path=application.path,
        application_type=application.application_type,
        name=application.name,
        private=private,
        use_cache=use_cache,
        **kwargs,
    ):
        response = self.update(application=application, private=private, use_cache=use_cache, **kwargs)
    else:
        response = self.create(application=application, private=private, use_cache=use_cache, **kwargs)
    return response

update_or_create_document_from_file(path, name, path_to_file, private=False, use_cache=False, **kwargs)

Update or create application from file

Automatically handles mixed public/private folder hierarchies.

Parameters:

Name Type Description Default
path str

application path on server, i.e. 'Finance/Reports'

required
name str

name of the application on server, i.e. 'Flash.xlsx'

required
path_to_file str

full local file path of file, i.e. 'C:\Users\User\Flash.xslx'

required
private bool

access level of the object

False
use_cache bool

boolean - whether to cache discovered private boundaries

False

Returns:

Type Description
Response

Response

Source code in TM1py/Services/ApplicationService.py
def update_or_create_document_from_file(
    self, path: str, name: str, path_to_file: str, private: bool = False, use_cache: bool = False, **kwargs
) -> Response:
    """Update or create application from file

    Automatically handles mixed public/private folder hierarchies.

    :param path: application path on server, i.e. 'Finance/Reports'
    :param name: name of the application on server, i.e. 'Flash.xlsx'
    :param path_to_file: full local file path of file, i.e. 'C:\\Users\\User\\Flash.xslx'
    :param private: access level of the object
    :param use_cache: boolean - whether to cache discovered private boundaries
    :return: Response
    """
    if self.exists(path=path, application_type=ApplicationTypes.DOCUMENT, name=name, private=private,
                   use_cache=use_cache, **kwargs):
        response = self.update_document_from_file(
            path_to_file=path_to_file, application_path=path, application_name=name, private=private,
            use_cache=use_cache, **kwargs
        )
    else:
        response = self.create_document_from_file(
            path_to_file=path_to_file, application_path=path, application_name=name, private=private,
            use_cache=use_cache, **kwargs
        )

    return response