Skip to content

Commit afbd039

Browse files
committed
fix issue #31
1 parent f4bbd2c commit afbd039

3 files changed

Lines changed: 73 additions & 59 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## Unreleased
22

3+
## 0.2.14.1
4+
### Changed
5+
- Fixed the issue #31 ([Unable to use get_columns_name_id as a non-superuser](https://github.com/vvaezian/metabase_api_python/issues/31))
36

47
## 0.2.14
58
### Added

metabase_api/metabase_api.py

Lines changed: 69 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
class 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'}

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="metabase-api",
8-
version="0.2.14",
8+
version="0.2.14.1",
99
author="Vahid Vaezian",
1010
author_email="vahid.vaezian@gmail.com",
1111
description="A Python Wrapper for Metabase API",

0 commit comments

Comments
 (0)