33
44class Metabase_API ():
55
6- def __init__ (self , domain , email , password = None , basic_auth = False ):
6+ def __init__ (self , domain , email , password = None , basic_auth = False , is_admin = True ):
77
88 self .domain = domain .rstrip ('/' )
99 self .email = email
@@ -12,6 +12,12 @@ def __init__(self, domain, email, password=None, basic_auth=False):
1212 self .header = None
1313 self .auth = (self .email , self .password ) if basic_auth else None
1414 self .authenticate ()
15+ self .is_admin = is_admin
16+ if not self .is_admin :
17+ print ('''
18+ Ask your Metabase admin to disable "Friendly Table and Field Names" (in Admin Panel > Settings > General).
19+ Without this some of the functions of the current package may not work as expected.
20+ ''' )
1521
1622
1723 def authenticate (self ):
@@ -333,8 +339,9 @@ def get_table_metadata(self, table_name=None, table_id=None, db_name=None, db_id
333339
334340
335341 def get_columns_name_id (self , table_name = None , db_name = None , table_id = None , db_id = None , verbose = False , column_id_name = False ):
336- '''Return a dictionary with col_name key and col_id value, for the given table_id/table_name in the given db_id/db_name.
337- If column_id_name is True, return a dictionary with col_id key and col_name value.
342+ '''
343+ Return a dictionary with col_name key and col_id value, for the given table_id/table_name in the given db_id/db_name.
344+ If column_id_name is True, return a dictionary with col_id key and col_name value.
338345 '''
339346 if not self .friendly_names_is_disabled ():
340347 raise ValueError ('Please disable "Friendly Table and Field Names" from Admin Panel > Settings > General, and try again.' )
@@ -365,10 +372,16 @@ def get_columns_name_id(self, table_name=None, db_name=None, table_id=None, db_i
365372
366373 def friendly_names_is_disabled (self ):
367374 '''
368- The endpoint /api/database/:db-id/fields which is used in the function get_column_name_id relies on the display name of fields.
375+ The endpoint /api/database/:db-id/fields which is used in the function get_columns_name_id relies on the display name of fields.
369376 If "Friendly Table and Field Names" (in Admin Panel > Settings > General) is not disabled, it changes the display name of fields.
370- So it is important to make sure this setting is disabled, before running the get_column_name_id function.
377+ So it is important to make sure this setting is disabled, before running the get_columns_name_id function.
371378 '''
379+ # checking whether friendly_name is disabled required admin access.
380+ # So to let non-admin users also use this package we skip this step for them.
381+ # There is warning in the __init__ method for these users.
382+ if not self .is_admin :
383+ return True
384+
372385 friendly_name_setting = [ i ['value' ] for i in self .get ('/api/setting' ) if i ['key' ] == 'humanization-strategy' ][0 ]
373386 return friendly_name_setting == 'none' # 'none' means disabled
374387
@@ -386,8 +399,8 @@ def verbose_print(verbose, msg):
386399 ##################################################################
387400
388401 def create_card (self , card_name = None , collection_name = None , collection_id = None ,
389- db_name = None , db_id = None , table_name = None , table_id = None ,
390- column_order = 'db_table_order' , custom_json = None , verbose = False , return_card = False ):
402+ db_name = None , db_id = None , table_name = None , table_id = None ,
403+ column_order = 'db_table_order' , custom_json = None , verbose = False , return_card = False ):
391404 """
392405 Create a card using the given arguments utilizing the endpoint 'POST /api/card/'.
393406 If collection is not given, the root collection is used.
@@ -508,9 +521,9 @@ def create_card(self, card_name=None, collection_name=None, collection_id=None,
508521 self .delete ("/api/card/{}" .format (card_id ))
509522
510523 column_name_id_dict = self .get_columns_name_id (db_id = db_id ,
511- table_id = table_id ,
512- table_name = table_name ,
513- verbose = verbose )
524+ table_id = table_id ,
525+ table_name = table_name ,
526+ verbose = verbose )
514527 column_id_list = [ column_name_id_dict [i ] for i in ordered_columns ]
515528 column_id_list_str = [ ['field-id' , i ] for i in column_id_list ]
516529
@@ -586,7 +599,7 @@ def create_collection(self, collection_name, parent_collection_id=None, parent_c
586599
587600
588601 def create_segment (self , segment_name , column_name , column_values , segment_description = '' ,
589- db_name = None , db_id = None , table_name = None , table_id = None , return_segment = False ):
602+ db_name = None , db_id = None , table_name = None , table_id = None , return_segment = False ):
590603 """
591604 Create a segment using the given arguments utilizing the endpoint 'POST /api/segment/'.
592605
@@ -630,10 +643,10 @@ def create_segment(self, segment_name, column_name, column_values, segment_descr
630643
631644
632645 def copy_card (self , source_card_name = None , source_card_id = None ,
633- source_collection_name = None , source_collection_id = None ,
634- destination_card_name = None ,
635- destination_collection_name = None , destination_collection_id = None ,
636- postfix = '' , verbose = False ):
646+ source_collection_name = None , source_collection_id = None ,
647+ destination_card_name = None ,
648+ destination_collection_name = None , destination_collection_id = None ,
649+ postfix = '' , verbose = False ):
637650 """
638651 Copy the card with the given name/id to the given destination collection.
639652
@@ -655,9 +668,9 @@ def copy_card(self, source_card_name=None, source_card_id=None,
655668 raise ValueError ('Either the name or id of the source card must be provided.' )
656669 else :
657670 source_card_id = self .get_item_id (item_type = 'card' ,
658- item_name = source_card_name ,
659- collection_id = source_collection_id ,
660- collection_name = source_collection_name )
671+ item_name = source_card_name ,
672+ collection_id = source_collection_id ,
673+ collection_name = source_collection_name )
661674
662675 if not destination_collection_id :
663676 if not destination_collection_name :
@@ -691,9 +704,9 @@ def copy_card(self, source_card_name=None, source_card_id=None,
691704
692705
693706 def copy_pulse (self , source_pulse_name = None , source_pulse_id = None ,
694- source_collection_name = None , source_collection_id = None ,
695- destination_pulse_name = None ,
696- destination_collection_id = None , destination_collection_name = None , postfix = '' ):
707+ source_collection_name = None , source_collection_id = None ,
708+ destination_pulse_name = None ,
709+ destination_collection_id = None , destination_collection_name = None , postfix = '' ):
697710 """
698711 Copy the pulse with the given name/id to the given destination collection.
699712
@@ -743,10 +756,10 @@ def copy_pulse(self, source_pulse_name=None, source_pulse_id=None,
743756
744757
745758 def copy_dashboard (self , source_dashboard_name = None , source_dashboard_id = None ,
746- source_collection_name = None , source_collection_id = None ,
747- destination_dashboard_name = None ,
748- destination_collection_name = None , destination_collection_id = None ,
749- deepcopy = False , postfix = '' ):
759+ source_collection_name = None , source_collection_id = None ,
760+ destination_dashboard_name = None ,
761+ destination_collection_name = None , destination_collection_id = None ,
762+ deepcopy = False , postfix = '' ):
750763 """
751764 Copy the dashboard with the given name/id to the given destination collection.
752765
@@ -771,8 +784,8 @@ def copy_dashboard(self, source_dashboard_name=None, source_dashboard_id=None,
771784 raise ValueError ('Either the name or id of the source dashboard must be provided.' )
772785 else :
773786 source_dashboard_id = self .get_item_id (item_type = 'dashboard' ,item_name = source_dashboard_name ,
774- collection_id = source_collection_id ,
775- collection_name = source_collection_name )
787+ collection_id = source_collection_id ,
788+ collection_name = source_collection_name )
776789
777790 if not destination_collection_id :
778791 if not destination_collection_name :
@@ -836,9 +849,9 @@ def copy_dashboard(self, source_dashboard_name=None, source_dashboard_id=None,
836849
837850
838851 def copy_collection (self , source_collection_name = None , source_collection_id = None ,
839- destination_collection_name = None ,
840- destination_parent_collection_name = None , destination_parent_collection_id = None ,
841- deepcopy_dashboards = False , postfix = '' , child_items_postfix = '' , verbose = False ):
852+ destination_collection_name = None ,
853+ destination_parent_collection_name = None , destination_parent_collection_id = None ,
854+ deepcopy_dashboards = False , postfix = '' , child_items_postfix = '' , verbose = False ):
842855 """
843856 Copy the collection with the given name/id into the given destination parent collection.
844857
@@ -883,10 +896,10 @@ def copy_collection(self, source_collection_name=None, source_collection_id=None
883896
884897 ### create a collection in the destination to hold the contents of the source collection
885898 res = self .create_collection (destination_collection_name ,
886- parent_collection_id = destination_parent_collection_id ,
887- parent_collection_name = destination_parent_collection_name ,
888- return_results = True
889- )
899+ parent_collection_id = destination_parent_collection_id ,
900+ parent_collection_name = destination_parent_collection_name ,
901+ return_results = True
902+ )
890903 destination_collection_id = res ['id' ]
891904
892905 ### get the items to copy
@@ -904,10 +917,10 @@ def copy_collection(self, source_collection_name=None, source_collection_id=None
904917 destination_collection_name = collection_name + child_items_postfix
905918 self .verbose_print (verbose , 'Copying the collection "{}" ...' .format (collection_name ))
906919 self .copy_collection (source_collection_id = collection_id ,
907- destination_parent_collection_id = destination_collection_id ,
908- child_items_postfix = child_items_postfix ,
909- deepcopy_dashboards = deepcopy_dashboards ,
910- verbose = verbose )
920+ destination_parent_collection_id = destination_collection_id ,
921+ child_items_postfix = child_items_postfix ,
922+ deepcopy_dashboards = deepcopy_dashboards ,
923+ verbose = verbose )
911924
912925 ## copy a dashboard
913926 if item ['model' ] == 'dashboard' :
@@ -927,8 +940,8 @@ def copy_collection(self, source_collection_name=None, source_collection_id=None
927940 destination_card_name = card_name + child_items_postfix
928941 self .verbose_print (verbose , 'Copying the card "{}" ...' .format (card_name ))
929942 self .copy_card (source_card_id = card_id ,
930- destination_collection_id = destination_collection_id ,
931- destination_card_name = destination_card_name )
943+ destination_collection_id = destination_collection_id ,
944+ destination_card_name = destination_card_name )
932945
933946 ## copy a pulse
934947 if item ['model' ] == 'pulse' :
@@ -965,7 +978,8 @@ def search(self, q, item_type=None, archived=False):
965978
966979
967980
968- def get_card_data (self , card_name = None , card_id = None , collection_name = None , collection_id = None , data_format = 'json' , parameters = None ):
981+ def get_card_data (self , card_name = None , card_id = None , collection_name = None ,
982+ collection_id = None , data_format = 'json' , parameters = None ):
969983 '''
970984 Run the query associated with a card and get the results.
971985 The data_format keyword specifies the format of the returned data:
@@ -983,9 +997,9 @@ def get_card_data(self, card_name=None, card_id=None, collection_name=None, coll
983997 if card_name is None :
984998 raise ValueError ('Either card_id or card_name must be provided.' )
985999 card_id = self .get_item_id (item_name = card_name ,
986- collection_name = collection_name ,
987- collection_id = collection_id ,
988- item_type = 'card' )
1000+ collection_name = collection_name ,
1001+ collection_id = collection_id ,
1002+ item_type = 'card' )
9891003
9901004 # add the filter values (if any)
9911005 import json
@@ -1002,12 +1016,11 @@ def get_card_data(self, card_name=None, card_id=None, collection_name=None, coll
10021016
10031017
10041018
1005- def clone_card (self , card_id
1006- , source_table_id = None , target_table_id = None
1007- , source_table_name = None , target_table_name = None
1008- , new_card_name = None , new_card_collection_id = None
1009- , ignore_these_filters = None
1010- , return_card = False ):
1019+ def clone_card (self , card_id ,
1020+ source_table_id = None , target_table_id = None ,
1021+ source_table_name = None , target_table_name = None ,
1022+ new_card_name = None , new_card_collection_id = None ,
1023+ ignore_these_filters = None , return_card = False ):
10111024 """
10121025 *** work in progress ***
10131026 Create a new card where the source of the old card is changed from 'source_table_id' to 'target_table_id'.
@@ -1099,8 +1112,8 @@ def clone_card(self, card_id
10991112
11001113
11011114
1102- def move_to_archive (self , item_type , item_name = None , item_id = None
1103- , collection_name = None , collection_id = None , table_id = None , verbose = False ):
1115+ def move_to_archive (self , item_type , item_name = None , item_id = None ,
1116+ collection_name = None , collection_id = None , table_id = None , verbose = False ):
11041117 '''Archive the given item. For deleting the item use the 'delete_item' function.'''
11051118 assert item_type in ['card' , 'dashboard' , 'collection' , 'pulse' , 'segment' ]
11061119
@@ -1129,8 +1142,8 @@ def move_to_archive(self, item_type, item_name=None, item_id=None
11291142
11301143
11311144
1132- def delete_item (self , item_type , item_name = None , item_id = None
1133- , collection_name = None , collection_id = None , verbose = False ):
1145+ def delete_item (self , item_type , item_name = None , item_id = None ,
1146+ collection_name = None , collection_id = None , verbose = False ):
11341147 '''
11351148 Delete the given item. Use carefully (this is different from archiving).
11361149 Currently Collections and Segments cannot be deleted using the Metabase API.
@@ -1145,10 +1158,8 @@ def delete_item(self, item_type, item_name=None, item_id=None
11451158
11461159
11471160
1148- def update_column (self , params ,
1149- column_id = None , column_name = None ,
1150- table_id = None , table_name = None ,
1151- db_id = None , db_name = None ):
1161+ def update_column (self , params , column_id = None , column_name = None ,
1162+ table_id = None , table_name = None , db_id = None , db_name = None ):
11521163 '''
11531164 Update the column in data model by providing values for 'params'.
11541165 E.g. for changing the column type to 'Category' in data model, use: params={'semantic_type':'type/Category'}
0 commit comments