def alter( self, name: Optional[str] = None, description: Optional[str] = None, datasource_type: Optional[Union[str, DatasourceType]] = None, table_prefix: Optional[str] = None, odbc_version: Optional[str] = None, intermediate_store_db_name: Optional[str] = None, intermediate_store_table_space_name: Optional[str] = None, dbms: Union[str, Dbms, None] = None, datasource_connection: Union[str, DatasourceConnection, None] = None, primary_datasource: Union[str, "DatasourceInstance", None] = None, data_mart_datasource: Union[str, "DatasourceInstance", None] = None ) -> None: """Alter DatasourceInstance properties. Args: name: Datasource name description: Datasource description datasource_type: DatasourceType Enum (reserved, normal, data_import, data_import_primary) table_prefix: Table prefix odbc_version: Odbc version ENUM (version3x, version2x) intermediate_store_db_name: Intermediate store DBName intermediate_store_table_space_name: intermediate store table space name dbms: The database management system (DBMS) object or ID datasource_connection: `DatasourceConnection` object or ID primary_datasource: `DatasourceInstance` object or ID data_mart_datasource: `DatasourceInstance` object or ID """ dbms = {'id': get_objects_id(dbms, Dbms)} if dbms else None datasource_connection = { 'id': get_objects_id(datasource_connection, DatasourceConnection) } if datasource_connection else None primary_datasource = { 'id': get_objects_id(primary_datasource, self) } if primary_datasource else None data_mart_datasource = { 'id': get_objects_id(data_mart_datasource, self) } if data_mart_datasource else None func = self.alter args = func.__code__.co_varnames[:func.__code__.co_argcount] defaults = func.__defaults__ # type: ignore default_dict = dict(zip(args[-len(defaults):], defaults)) if defaults else {} local = locals() properties = {} for property_key in default_dict.keys(): if local[property_key] is not None: properties[property_key] = local[property_key] self._alter_properties(**properties)
def alter(self, name: Optional[str] = None, description: Optional[str] = None, enabled: Optional[bool] = None, linked_user: Optional[Union['User', str]] = None, contact_addresses: Optional[Iterable[Union['ContactAddress', dict]]] = None): """Update properties of a contact Args: name: name of a contact description: description of a contact enabled: specifies if a contact is enabled linked_user: an object of class User linked to the contact contact_addresses: list of contact addresses """ linked_user = {'id': get_objects_id(linked_user, User)} if linked_user else None func = self.alter args = func.__code__.co_varnames[:func.__code__.co_argcount] defaults = func.__defaults__ # type: ignore defaults_dict = dict(zip(args[-len(defaults):], defaults)) if defaults else {} local = locals() properties = defaultdict(dict) for property_key in defaults_dict: if local[property_key] is not None: properties[property_key] = local[property_key] self._alter_properties(**properties)
def quick_search_from_object(connection: Connection, project: Union[Project, str], search_object: Union[SearchObject, str], include_ancestors: bool = False, include_acl: bool = False, subtypes: Optional[Union[ObjectSubTypes, List[ObjectSubTypes], int, List[int]]] = None, limit: Optional[int] = None, offset: Optional[int] = None, to_dictionary: bool = True): """Perform a quick search based on a predefined Search Object. Use an existing search object for Quick Search engine to return search results and display them as a list. Args: connection (object): MicroStrategy connection object returned by `connection.Connection()` project (string): `Project` object or ID search_object(SearchObject): Search object ID to retrieve result from include_ancestors(bool): Specifies whether to return the list of ancestors for each object include_acl(bool): Specifies whether to return the list of ACL for each object subtypes(list, int): This parameter is used to filter the objects in the result to include only the ones whose “subtype” is included in the values of this parameter limit (int): limit the number of elements returned. If `None` (default), all objects are returned. offset (int): Starting point within the collection of returned results. Used to control paging behavior. Default is 0. to_dictionary (bool): If True returns dicts, by default (False) returns objects. Returns: list of objects or list of dictionaries """ from mstrio.utils.object_mapping import map_objects_list project_id = get_objects_id(project, Project) search_object_id = get_objects_id(search_object, SearchObject) subtypes = get_enum_val(subtypes, ObjectSubTypes) resp = browsing.get_quick_search_result_from_object(connection, project_id, search_object_id, subtypes=subtypes, include_ancestors=include_ancestors, include_acl=include_acl, limit=limit, offset=offset) objects = resp.json()["result"] if to_dictionary: return objects return map_objects_list(connection, objects)
def create(cls, connection: "Connection", name: str, device_type: Union[DeviceType, str], transmitter: Union[Transmitter, str], device_properties: Union[dict, Dictable], description: str = None) -> "Device": """Create a new device. Args: connection: MicroStrategy connection object returned by `connection.Connection()` name: device object name device_type: type of the device transmitter: Transmitter object description: device object description device_properties: properties of the device Returns: Device object. """ device_type = get_enum_val(device_type, DeviceType) device_properties = device_properties.to_dict() if isinstance( device_properties, Dictable) else device_properties transmitter_id = get_objects_id(transmitter, Transmitter) body = { "name": name, "description": description, "deviceType": device_type, "transmitter": { "id": transmitter_id, }, "deviceProperties": { device_type: device_properties } } body = delete_none_values(body) response = devices.create_device(connection, body).json() if config.verbose: logger.info( f"Successfully created device named: '{name}' with ID: '{response['id']}'." ) return cls.from_dict(source=response, connection=connection)
def create(cls, connection: "Connection", name: str, linked_user: Union[str, User], members: List[Union[dict, ContactGroupMember]], description: Optional[str] = None, enabled: bool = True) -> 'ContactGroup': """Create a new contact group. Args: connection: MicroStrategy connection object returned by `connection.Connection()` name: contact group name linked_user: user linked to contact members: list of members description: description of contact enabled: specifies if contact should be enabled Returns: `ContactGroup` object """ members = [ m.to_dict() if isinstance(m, ContactGroupMember) else m for m in members ] linked_user = get_objects_id(linked_user, User) body = { 'name': name, 'description': description, 'enabled': enabled, 'linkedUser': { 'id': linked_user }, 'members': members } res = contact_groups.create_contact_group(connection, body).json() if config.verbose: logger.info( f"Successfully created contact group named: '{res.get('name')}' " f"with ID: '{res.get('id')}'") return cls.from_dict(res, connection)
def get_search_results(connection: Connection, search_id: str, project: Optional[Union[Project, str]] = None, results_format: SearchResultsFormat = SearchResultsFormat.LIST, limit: Optional[int] = None, offset: Optional[int] = None, to_dictionary: bool = False, **filters): """Retrieve the results of a full metadata search previously stored in an instance in IServer memory, may be obtained by `start_full_search`. Args: connection (object): MicroStrategy connection object returned by `connection.Connection()` search_id (str): Search ID (identifies the results of a previous search stored in IServer memory) project (string): `Project` object or ID results_format(SearchResultsFormat): either a list or a tree format to_dictionary (bool): If True returns dicts, by default (False) returns objects. limit (int): limit the number of elements returned. If `None` (default), all objects are returned. offset (int): Starting point within the collection of returned results. Used to control paging behavior. Default is 0. **filters: Available filter parameters: ['id', 'name', 'description', 'date_created', 'date_modified', 'acg'] Returns: list of objects or list of dictionaries """ passed_params = locals() get_result_args = get_args_from_func(_get_search_result_tree_format) get_result_params = {k: v for k, v in passed_params.items() if k in get_result_args} project_id = get_objects_id(project, Project) get_result_params['project_id'] = project_id if results_format == SearchResultsFormat.TREE: logger.info( 'Notice. When results_format is equal to TREE, results are always returned' ' in a dictionary format.' ) return _get_search_result_tree_format(**get_result_params) get_result_params.update({**filters, 'to_dictionary': to_dictionary}) return _get_search_result_list_format(**get_result_params)
def create(cls, connection: 'Connection', name: str, linked_user: Union['User', str], contact_addresses: Iterable[Union['ContactAddress', dict]], description: Optional[str] = None, enabled: bool = True) -> 'Contact': """Create a new contact. Args: connection: MicroStrategy connection object returned by `connection.Connection()` name: contact name linked_user: user linked to contact contact_addresses: list of contact addresses description: description of contact enabled: specifies if contact should be enabled Returns: Contact object """ body = { 'name': name, 'description': description, 'enabled': enabled, 'linkedUser': { 'id': get_objects_id(linked_user, User) }, 'contactAddresses': [ address.to_dict() if isinstance(address, ContactAddress) else address for address in contact_addresses ], } body = delete_none_values(body) response = contacts.create_contact(connection, body).json() if config.verbose: logger.info( f"Successfully created contact named: '{name}' with ID: '{response['id']}'" ) return cls.from_dict(source=response, connection=connection)
def get_search_suggestions(connection: Connection, project: Optional[Union[Project, str]] = None, key: Optional[str] = None, max_results: int = 4, cross_cluster: Optional[bool] = None) -> List[str]: """Request search suggestions from the server. Args: connection (object): MicroStrategy REST API connection object project (string, optional): `Project` object or ID key (string, optional): value the search pattern is set to, which will be applied to the names of suggestions being searched max_results (int, optional): maximum number of items returned for a single request. Used to control paging behavior. Default value is `-1` for no limit. cross_cluster (bool, optional): perform search in all unique projects across the cluster, this parameter only takes effect for I-Server with cluster nodes. Default value is `None` Returns: list of search suggestions """ project_id = get_objects_id(project, Project) return browsing.get_search_suggestions( connection=connection, project_id=project_id, key=key, count=max_results, is_cross_cluster=cross_cluster).json().get('suggestions')
def create( cls, connection: "Connection", name: str, description: Optional[str] = None, acg: Optional[int] = None, execution_mode: Union[str, ExecutionMode] = None, max_cancel_attempt_time: Optional[int] = None, max_query_exe_time: Optional[int] = None, max_connection_attempt_time: Optional[int] = None, connection_lifetime: Optional[int] = None, connection_idle_timeout: Optional[int] = None, char_encoding_windows: Union[str, CharEncoding] = None, char_encoding_unix: Union[str, CharEncoding] = None, table_prefix: Optional[str] = None, connection_string: Optional[str] = None, parameterized_queries: Optional[bool] = None, extended_fetch: Optional[bool] = None, datasource_login: Union[DatasourceLogin, str, None] = None, database_type: Optional[str] = None, database_version: Optional[str] = None, driver_type: Union[str, DriverType] = None, oauth_parameter: Optional[str] = None) -> "DatasourceConnection": """Create a new datasource connection on the I-Server. Args: connection: MicroStrategy connection object returned by `connection.Connection()`. name: Unique datasource connection name. description: Datasource connection description. acg: Object access rights. It's a bit vector where bits are defined at [EnumDSSXMLAccessRightFlags]. execution_mode: ExecutionMode Enum specifying how SQL statements will be executed on a physical database connection made. max_cancel_attempt_time: Number of seconds before being timed out when attempting to make a connection. max_query_exe_time: Number of seconds during which a query must be executed before being timed out. max_connection_attempt_time: Number of seconds connection attempts to be made before timing out. connection_lifetime: Number of seconds of the connection lifetime. connection_idle_timeout: Number of seconds before being timed out when the connection is idle. char_encoding_windows: CharEncoding Enum specifying the encoding across connection for Windows drivers. char_encoding_unix: CharEncoding Enum specifying the encoding across connection for Unix drivers. table_prefix: String prefixed to the names of all temporary tables created by the Query Engine for this connection during report execution with this string. connection_string: Database connection string. parameterized_queries: Specifies whether parameterized queries are enabled. extended_fetch: Specifies whether or not to use the extended fetch ODBC call to retrieve data from the database connection. driver_type: DriverType Enum specifying Driver used for database connection. oauth_parameter: Used for authentication with oAuth. datasource_login: `DatasourceLogin` object or ID database_type: Database type database_version: Database version Returns: DatasourceConnection object. """ login_id = get_objects_id(datasource_login, DatasourceLogin) body = { "name": name, "description": description, "acg": acg, "executionMode": get_enum_val(execution_mode, ExecutionMode), "maxCancelAttemptTime": max_cancel_attempt_time, "maxQueryExeTime": max_query_exe_time, "maxConnectionAttemptTime": max_connection_attempt_time, "connectionLifetime": connection_lifetime, "connectionIdleTimeout": connection_idle_timeout, "charEncodingWindows": get_enum_val(char_encoding_windows, CharEncoding), "charEncodingUnix": get_enum_val(char_encoding_unix, CharEncoding), "tablePrefix": table_prefix, "connectionString": connection_string, "parameterizedQueries": parameterized_queries, "extendedFetch": extended_fetch, "database": { "login": { "id": login_id }, "type": database_type, "version": database_version }, "driverType": get_enum_val(driver_type, DriverType), "oauthParameter": oauth_parameter } body = helper.delete_none_values(body) response = datasources.create_datasource_connection(connection, body).json() if config.verbose: logger.info( f"Successfully created datasource connection named: '{response.get('name')}' " f"with ID: '{response.get('id')}'") return cls.from_dict(source=response, connection=connection)
def alter( self, name: Optional[str] = None, description: Optional[str] = None, execution_mode: Union[str, ExecutionMode] = None, max_cancel_attempt_time: Optional[int] = None, max_query_exe_time: Optional[int] = None, max_connection_attempt_time: Optional[int] = None, connection_lifetime: Optional[int] = None, connection_idle_timeout: Optional[int] = None, char_encoding_windows: Union[str, CharEncoding] = None, char_encoding_unix: Union[str, CharEncoding] = None, table_prefix: Optional[str] = None, connection_string: Optional[str] = None, parameterized_queries: bool = None, extended_fetch: bool = None, driver_type: Union[str, DriverType] = None, database_type: Optional[str] = None, database_version: Optional[str] = None, datasource_login: Union[str, DatasourceLogin, None] = None) -> None: """Alter the datasource connection properties. Args: name: Unique datasource connection name. description: Datasource connection description. execution_mode: ExecutionMode Enum specifying how SQL statements will be executed on a physical database connection made. max_cancel_attempt_time: Number of seconds before being timed out when attempting to make a connection. max_query_exe_time: Number of seconds during which a query must be executed before being timed out. max_connection_attempt_time: Number of seconds connection attempts to be made before timing out. connection_lifetime: Number of seconds of the connection lifetime. connection_idle_timeout: Number of seconds before being timed out when the connection is idle. char_encoding_windows: CharEncoding Enum specifying the encoding across connection for Windows drivers. char_encoding_unix: CharEncoding Enum specifying the encoding across connection for Unix drivers. table_prefix: String prefixed to the names of all temporary tables created by the Query Engine for this connection during report execution with this string. connection_string: Database connection string. parameterized_queries: Specifies whether parameterized queries are enabled. extended_fetch: Specifies whether or not to use the extended fetch ODBC call to retrieve data from the database connection. driver_type: DriverType Enum specifying Driver used for database connection. datasource_login: `DatasourceLogin` object or ID driver_type: ENUM Drivers used for database connection. database_type: Database type database_version: Database version """ datasource_login = { 'id': get_objects_id(datasource_login, DatasourceLogin) } if datasource_login else None func = self.alter args = func.__code__.co_varnames[:func.__code__.co_argcount] defaults = func.__defaults__ # type: ignore default_dict = dict(zip(args[-len(defaults):], defaults)) if defaults else {} local = locals() properties = {} for property_key in default_dict.keys(): if local[property_key] is not None: properties[property_key] = local[property_key] self._alter_properties(**properties)
def quick_search(connection: Connection, project: Optional[Union[Project, str]] = None, name: Optional[str] = None, root: Optional[str] = None, pattern: Union[SearchPattern, int] = SearchPattern.CONTAINS, object_types: Optional["TypeOrSubtype"] = None, get_ancestors: bool = False, cross_cluster: bool = False, hidden: Optional[bool] = None, certified_status: CertifiedStatus = CertifiedStatus.ALL, limit: Optional[int] = None, offset: Optional[int] = None, to_dictionary: bool = True): """Use the stored results of the Quick Search engine to return search results and display them as a list. The Quick Search engine periodically indexes the metadata and stores the results in memory, making Quick Search very fast but with results that may not be the most recent. Args: connection (object): MicroStrategy connection object returned by `connection.Connection()` project (string): `Project` object or ID name(string): Value the search pattern is set to, which will be applied to the names of object types being searched. For example, search for all report objects (type) whose name begins with (patter) B (name). root(string, optional): Folder ID of the root folder where the search will be performed. pattern(integer or enum class object): Pattern to search for, such as Begin With or Exactly. Possible values are available in ENUM mstrio.browsing.SearchPattern. Default value is CONTAINS (4). object_types(enum class object or integer or list of enum class objects or integers): Type(s) of object(s) to be searched, such as Folder, Attribute or User. Possible values available in ENUMs mstrio.utils.entity.ObjectTypes and mstrio.utils.entity.ObjectSubTypes get_ancestors(bool): Specifies whether to return the list of ancestors for each object certified_status(CertifiedStatus): Defines a search criteria based on the certified status of the object, possible values available in CertifiedStatus enum cross_cluster(bool): Perform search in all unique projects across the cluster,this parameter only takes affect for I-Server with cluster nodes. hidden(bool): Filter the result based on the 'hidden' field of objects. If not passed, no filtering is applied. limit (int): limit the number of elements returned. If `None` (default), all objects are returned. offset (int): Starting point within the collection of returned results. Used to control paging behavior. Default is 0. to_dictionary (bool): If True returns dicts, by default (False) returns objects. Returns: list of objects or list of dictionaries """ from mstrio.utils.object_mapping import map_objects_list project_id = get_objects_id(project, Project) if object_types and not isinstance(object_types, list): object_types = [get_enum_val(object_types, (ObjectTypes, ObjectSubTypes))] elif object_types: object_types = [get_enum_val(t, (ObjectTypes, ObjectSubTypes)) for t in object_types] pattern = get_enum_val(pattern, SearchPattern) certified_status = get_enum_val(certified_status, CertifiedStatus) resp = browsing.get_quick_search_result(connection, project_id=project_id, name=name, pattern=pattern, object_types=object_types, root=root, get_ancestors=get_ancestors, hidden=hidden, cross_cluster=cross_cluster, limit=limit, certified_status=certified_status, offset=offset) objects = resp.json()["result"] if to_dictionary: return objects return map_objects_list(connection, objects)
def start_full_search(connection: Connection, project: Optional[Union[Project, str]] = None, name: Optional[str] = None, object_types: Optional["TypeOrSubtype"] = None, pattern: Union[SearchPattern, int] = SearchPattern.CONTAINS, domain: Union[SearchDomain, int] = SearchDomain.PROJECT, root: Optional[str] = None, uses_object_id: Optional[Union[EntityBase, str]] = None, uses_object_type: Optional[Union[ObjectTypes, ObjectSubTypes, int]] = None, uses_recursive: bool = False, uses_one_of: bool = False, used_by_object_id: Optional[Union[EntityBase, str]] = None, used_by_object_type: Optional[Union[ObjectTypes, ObjectSubTypes, int]] = None, used_by_recursive: bool = False, used_by_one_of: bool = False) -> dict: """Search the metadata for objects in a specific project that match specific search criteria, and save the results in IServer memory. Args: connection (object): MicroStrategy connection object returned by `connection.Connection()` project (string): `Project` object or ID object_types(enum class object or integer or list of enum class objects or integers): Type(s) of object(s) to be searched, such as Folder, Attribute or User. Possible values available in ENUMs mstrio.utils.entity.ObjectTypes and mstrio.utils.entity.ObjectSubTypes name(string): Value the search pattern is set to, which will be applied to the names of object types being searched. For example, search for all report objects (type) whose name begins with (patter) B (name). pattern(integer or enum class object): Pattern to search for, such as Begin With or Exactly. Possible values are available in ENUM mstrio.browsing.SearchPattern. Default value is CONTAINS (4). domain(integer or enum class object): Domain where the search will be performed, such as Local or Project. Possible values are available in ENUM mstrio.browsing.SearchDomain. Default value is PROJECT (2). root(string, optional): Folder ID of the root folder where the search will be performed. uses_object_id(string): Constrain the search to only return objects which use the given object. uses_object_type(int, ObjectTypes): Constrain the search to only return objects which use the given object. Possible values available in ENUMs mstrio.utils.entity.ObjectTypes uses_recursive(boolean): Control the Intelligence server to also find objects that use the given objects indirectly. Default value is false. uses_one_of(boolean): Control the Intelligence server to also find objects that use one of or all of given objects indirectly. Default value is false. used_by_object_id(string): Constrain the search to only return objects which are used by the given object. used_by_object_type(int, ObjectTypes): Constrain the search to only return objects which are used by the given object. Possible values available in ENUM mstrio.utils.entity.ObjectTypes used_by_recursive(boolean, optional): Control the Intelligence server to also find objects that are used by the given objects indirectly. Default value is false. used_by_one_of(boolean): Control the Intelligence server to also find objects that are used by one of or all of given objects indirectly. Default value is false. Returns: dictionary consisting of id (Search ID) and total items number """ if uses_object_id and used_by_object_id: exception_handler( msg="It is not allowed to use both ‘uses_object’ and ‘used_by_object’ in one request.", exception_type=AttributeError) uses_object = merge_id_and_type( uses_object_id, uses_object_type, "Please provide both `uses_object_id` and `uses_object_type`.") if uses_object_id else None used_by_object = merge_id_and_type( used_by_object_id, used_by_object_type, "Please provide both `used_by_object_id` and `uses_object_type`." ) if used_by_object_id else None project_id = get_objects_id(project, Project) if object_types and not isinstance(object_types, list): object_types = [get_enum_val(object_types, (ObjectTypes, ObjectSubTypes))] elif object_types: object_types = [get_enum_val(t, (ObjectTypes, ObjectSubTypes)) for t in object_types] pattern = get_enum_val(pattern, SearchPattern) domain = get_enum_val(domain, SearchDomain) resp = browsing.store_search_instance( connection=connection, project_id=project_id, name=name, pattern=pattern, domain=domain, root=root, object_types=object_types, uses_object=uses_object, uses_recursive=uses_recursive, uses_one_of=uses_one_of, used_by_object=used_by_object, used_by_recursive=used_by_recursive, used_by_one_of=used_by_one_of, ) return resp.json()
def create( cls, connection: "Connection", name: str, dbms: Union[Dbms, str], description: Optional[str] = None, datasource_type: Optional[Union[str, DatasourceType]] = None, table_prefix: Optional[str] = None, odbc_version: Optional[str] = None, intermediate_store_db_name: Optional[str] = None, intermediate_store_table_space_name: Optional[str] = None, datasource_connection: Union[str, DatasourceConnection, None] = None, database_type: str = None, database_version: str = None, primary_datasource: Union[str, "DatasourceInstance", None] = None, data_mart_datasource: Union[str, "DatasourceInstance", None] = None ) -> Optional["DatasourceInstance"]: """Create a new DatasourceInstance object on I-Server. Args: connection: MicroStrategy connection object returned by `connection.Connection()`. name: Datasource name dbms: The database management system (DBMS) object or id description: Datasource description datasource_type: DatasourceType Enum (reserved, normal, data_import, data_import_primary) table_prefix: Table prefix odbc_version: Odbc version ENUM (version3x, version2x) intermediate_store_db_name: Intermediate store DBName intermediate_store_table_space_name: intermediate store table space name datasource_connection: `DatasourceConnection` object or ID database_type: Database type database_version: Database version primary_datasource: `DatasourceInstance` object or ID data_mart_datasource: `DatasourceInstance` object or ID Returns: DatasourceInstance object. """ dbms_id = get_objects_id(dbms, Dbms) connection_id = get_objects_id(datasource_connection, DatasourceConnection) primary_datasource_id = get_objects_id(primary_datasource, cls) data_mart_datasource_id = get_objects_id(data_mart_datasource, cls) database = { "type": database_type, "version": database_version, "connection": { "id": connection_id } } if primary_datasource_id: database["primaryDatasource"] = {"id": primary_datasource_id} if data_mart_datasource_id: database["dataMartDatasource"] = {"id": data_mart_datasource_id} body = { "name": name, "database": database, "description": description, "datasourceType": get_enum_val(datasource_type, DatasourceType), "tablePrefix": table_prefix, "odbcVersion": odbc_version, "intermediateStoreDbName": intermediate_store_db_name, "intermediateStoreTableSpaceName": intermediate_store_table_space_name, "dbms": { "id": dbms_id } } body = helper.delete_none_values(body) response = datasources.create_datasource_instance(connection, body).json() if config.verbose: logger.info( f"Successfully created datasource instance named: '{response.get('name')}' " f"with ID: '{response.get('id')}'") return cls.from_dict(source=response, connection=connection)
def create(cls, connection: Connection, project: Union[Project, str], user: Union[User, str], ds_connection: Union[DatasourceConnection, str], datasource: Union[DatasourceInstance, str], login: Union[DatasourceLogin, str], locale: Optional[Locale] = None, locale_id: Optional[str] = None, locale_name: Optional[str] = None) -> "DatasourceMap": """Create a new Datasource Map object on the server. If more than one locale related parameters are provided, `locale` has priority, then `locale_id`. Args: connection: A MicroStrategy connection object project: The project the Map is to be assigned to user: The User to be mapped ds_connection: The Datasource Connection to be mapped datasource: The Datasource Instance to be mapped login: The Datasource Login to be mapped locale: The locale to be mapped. locale_id: The id of locale to be mapped. locale_name: The name of locale to be mapped. Returns: DatasourceMap object """ project_id = get_objects_id(project, Project) user_id = get_objects_id(user, User) connection_id = get_objects_id(ds_connection, DatasourceConnection) datasource_id = get_objects_id(datasource, DatasourceInstance) login_id = get_objects_id(login, DatasourceLogin) body = { "projectId": project_id, "user": { "id": user_id }, "connection": { "id": connection_id }, "datasource": { "id": datasource_id }, "login": { "id": login_id }, } if locale and isinstance(locale, Locale): body["locale"] = locale.to_dict() elif locale_id and isinstance(locale_id, str): body["locale"] = {"id": locale} elif locale_name and isinstance(locale_name, str): body["locale"] = {"name": locale} jresponse = datasources.create_datasource_mapping( connection=connection, body=body).json() if config.verbose: logger.info( f"Successfully created datasource connection map with ID: '{jresponse.get('id')}'" ) return cls.from_dict(source=helper.camel_to_snake(jresponse), connection=connection)