diff --git a/src/metabase/metabase.py b/src/metabase/metabase.py index a47b6be..0fbf20e 100644 --- a/src/metabase/metabase.py +++ b/src/metabase/metabase.py @@ -1,21 +1,9 @@ -from weakref import WeakValueDictionary - import requests from metabase.exceptions import AuthenticationError -class Singleton(type): - _instances = WeakValueDictionary() - - def __call__(cls, *args, **kw): - if cls not in cls._instances: - instance = super(Singleton, cls).__call__(*args, **kw) - cls._instances[cls] = instance - return cls._instances[cls] - - -class Metabase(metaclass=Singleton): +class Metabase: def __init__(self, host: str, user: str, password: str, token: str = None): self._host = host self.user = user diff --git a/src/metabase/resource.py b/src/metabase/resource.py index 4145d9a..409c35c 100644 --- a/src/metabase/resource.py +++ b/src/metabase/resource.py @@ -11,8 +11,9 @@ class Resource: ENDPOINT: str PRIMARY_KEY: str = "id" - def __init__(self, **kwargs): + def __init__(self, _using: Metabase, **kwargs): self._attributes = [] + self._using = _using for k, v in kwargs.items(): self._attributes.append(k) @@ -31,42 +32,38 @@ def __repr__(self): + ")" ) - @staticmethod - def connection() -> Metabase: - return Metabase() - class ListResource(Resource): @classmethod - def list(cls): + def list(cls, using: Metabase): """List all instances.""" - response = cls.connection().get(cls.ENDPOINT) - records = [cls(**record) for record in response.json()] + response = using.get(cls.ENDPOINT) + records = [cls(_using=using, **record) for record in response.json()] return records class GetResource(Resource): @classmethod - def get(cls, id: int): + def get(cls, id: int, using: Metabase): """Get a single instance by ID.""" - response = cls.connection().get(cls.ENDPOINT + f"/{id}") + response = using.get(cls.ENDPOINT + f"/{id}") if response.status_code == 404 or response.status_code == 204: raise NotFoundError(f"{cls.__name__}(id={id}) was not found.") - return cls(**response.json()) + return cls(_using=using, **response.json()) class CreateResource(Resource): @classmethod - def create(cls, **kwargs): + def create(cls, using: Metabase, **kwargs): """Create an instance and save it.""" - response = cls.connection().post(cls.ENDPOINT, json=kwargs) + response = using.post(cls.ENDPOINT, json=kwargs) if response.status_code not in (200, 202): raise HTTPError(response.content.decode()) - return cls(**response.json()) + return cls(_using=using, **response.json()) class UpdateResource(Resource): @@ -77,7 +74,7 @@ def update(self, **kwargs) -> None: ignored from the request. """ params = {k: v for k, v in kwargs.items() if v != MISSING} - response = self.connection().put( + response = self._using.put( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}", json=params ) @@ -91,7 +88,7 @@ def update(self, **kwargs) -> None: class DeleteResource(Resource): def delete(self) -> None: """Delete an instance.""" - response = self.connection().delete( + response = self._using.delete( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" ) diff --git a/src/metabase/resources/card.py b/src/metabase/resources/card.py index f4c70d9..bf8570d 100644 --- a/src/metabase/resources/card.py +++ b/src/metabase/resources/card.py @@ -2,6 +2,7 @@ from typing import List +from metabase import Metabase from metabase.missing import MISSING from metabase.resource import CreateResource, GetResource, ListResource, UpdateResource @@ -41,7 +42,7 @@ class Card(ListResource, CreateResource, GetResource, UpdateResource): created_at: str @classmethod - def list(cls) -> List[Card]: + def list(cls, using: Metabase) -> List[Card]: """ Get all the Cards. Option filter param f can be used to change the set of Cards that are returned; default is all, but other options include @@ -51,18 +52,19 @@ def list(cls) -> List[Card]: of each filter option. :card_index:. """ # TODO: add support for endpoint parameters: f, model_id. - return super(Card, cls).list() + return super(Card, cls).list(using) @classmethod - def get(cls, id: int) -> Card: + def get(cls, id: int, using: Metabase) -> Card: """ Get Card with ID. """ - return super(Card, cls).get(id) + return super(Card, cls).get(id, using) @classmethod def create( cls, + using: Metabase, name: str, dataset_query: dict, # TODO: DatasetQuery visualization_settings: dict, # TODO: VisualizationSettings @@ -79,6 +81,7 @@ def create( Create a new Card. """ return super(Card, cls).create( + using=using, name=name, dataset_query=dataset_query, visualization_settings=visualization_settings, @@ -129,7 +132,7 @@ def update( ) def archive(self): - """Archive a Metric.""" + """Archive a Card.""" return self.update( archived=True, revision_message="Archived by metabase-python." ) diff --git a/src/metabase/resources/database.py b/src/metabase/resources/database.py index 4c6b7d8..5bbe56a 100644 --- a/src/metabase/resources/database.py +++ b/src/metabase/resources/database.py @@ -2,6 +2,7 @@ from typing import Any, Dict, List +from metabase import Metabase from metabase.missing import MISSING from metabase.resource import ( CreateResource, @@ -47,18 +48,19 @@ class Database( created_at: str @classmethod - def list(cls) -> List[Database]: - response = cls.connection().get(cls.ENDPOINT) - records = [cls(**db) for db in response.json().get("data", [])] + def list(cls, using: Metabase) -> List[Database]: + response = using.get(cls.ENDPOINT) + records = [cls(_using=using, **db) for db in response.json().get("data", [])] return records @classmethod - def get(cls, id: int) -> Database: - return super(Database, cls).get(id) + def get(cls, id: int, using: Metabase) -> Database: + return super(Database, cls).get(id, using=using) @classmethod def create( cls, + using: Metabase, name: str, engine: str, details: dict, @@ -75,6 +77,7 @@ def create( You must be a superuser to do this. """ return super(Database, cls).create( + using=using, name=name, engine=engine, details=details, @@ -128,43 +131,33 @@ def delete(self) -> None: def fields(self) -> List[Field]: """Get a list of all Fields in Database.""" - fields = ( - self.connection() - .get(self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/fields") - .json() - ) - return [Field(**payload) for payload in fields] + fields = self._using.get( + self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/fields" + ).json() + return [Field(_using=self._using, **payload) for payload in fields] def idfields(self) -> List[Field]: """Get a list of all primary key Fields for Database.""" - fields = ( - self.connection() - .get(self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/idfields") - .json() - ) - return [Field(**payload) for payload in fields] + fields = self._using.get( + self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/idfields" + ).json() + return [Field(_using=self._using, **payload) for payload in fields] def schemas(self) -> List[str]: """Returns a list of all the schemas found for the database id.""" - return ( - self.connection() - .get(self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/schemas") - .json() - ) + return self._using.get( + self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/schemas" + ).json() def tables(self, schema: str) -> List[Table]: """Returns a list of Tables for the given Database id and schema.""" - tables = ( - self.connection() - .get( - self.ENDPOINT - + f"/{getattr(self, self.PRIMARY_KEY)}" - + "/schema" - + f"/{schema}" - ) - .json() - ) - return [Table(**payload) for payload in tables] + tables = self._using.get( + self.ENDPOINT + + f"/{getattr(self, self.PRIMARY_KEY)}" + + "/schema" + + f"/{schema}" + ).json() + return [Table(_using=self._using, **payload) for payload in tables] def discard_values(self): """ @@ -172,7 +165,7 @@ def discard_values(self): You must be a superuser to do this. """ - return self.connection().post( + return self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/discard_values" ) @@ -182,13 +175,13 @@ def rescan_values(self): You must be a superuser to do this. """ - return self.connection().post( + return self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/rescan_values" ) def sync(self): """Update the metadata for this Database. This happens asynchronously.""" - return self.connection().post( + return self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/sync" ) @@ -198,6 +191,6 @@ def sync_schema(self): You must be a superuser to do this. """ - return self.connection().post( + return self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/sync_schema" ) diff --git a/src/metabase/resources/dataset.py b/src/metabase/resources/dataset.py index a25de97..ab83548 100644 --- a/src/metabase/resources/dataset.py +++ b/src/metabase/resources/dataset.py @@ -4,6 +4,7 @@ import pandas as pd +from metabase import Metabase from metabase.resource import CreateResource, Resource @@ -37,10 +38,14 @@ class Dataset(CreateResource): average_execution_time: int = None @classmethod - def create(cls, database: int, type: str, query: dict, **kwargs) -> Dataset: + def create( + cls, using: Metabase, database: int, type: str, query: dict, **kwargs + ) -> Dataset: """Execute a query and retrieve the results in the usual format.""" - dataset = super(Dataset, cls).create(database=database, type=type, query=query) - dataset.data = Data(**dataset.data) + dataset = super(Dataset, cls).create( + using=using, database=database, type=type, query=query + ) + dataset.data = Data(_using=using, **dataset.data) return dataset def to_pandas(self) -> pd.DataFrame: diff --git a/src/metabase/resources/field.py b/src/metabase/resources/field.py index 5831b15..66353ee 100644 --- a/src/metabase/resources/field.py +++ b/src/metabase/resources/field.py @@ -3,6 +3,7 @@ from enum import Enum from typing import Any, Dict, List, Optional +from metabase import Metabase from metabase.missing import MISSING from metabase.resource import GetResource, UpdateResource @@ -111,9 +112,9 @@ class VisibilityType(str, Enum): sensitive = "sensitive" @classmethod - def get(cls, id: int) -> Field: + def get(cls, id: int, using: Metabase) -> Field: """Get Field with ID.""" - return super(Field, cls).get(id) + return super(Field, cls).get(id, using=using) def update( self, @@ -145,11 +146,9 @@ def update( def related(self) -> Dict[str, Any]: """Return related entities.""" - return ( - self.connection() - .get(self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/related") - .json() - ) + return self._using.get( + self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/related" + ).json() def discard_values(self): """ @@ -159,7 +158,7 @@ def discard_values(self): You must be a superuser to do this. """ - return self.connection().post( + return self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/discard_values" ) @@ -170,6 +169,6 @@ def rescan_values(self): You must be a superuser to do this. """ - return self.connection().post( + return self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/rescan_values" ) diff --git a/src/metabase/resources/metric.py b/src/metabase/resources/metric.py index d803b89..2bebab0 100644 --- a/src/metabase/resources/metric.py +++ b/src/metabase/resources/metric.py @@ -3,6 +3,7 @@ from datetime import datetime from typing import List +from metabase import Metabase from metabase.missing import MISSING from metabase.resource import CreateResource, GetResource, ListResource, UpdateResource @@ -31,16 +32,17 @@ class Metric(ListResource, CreateResource, GetResource, UpdateResource): creator: dict @classmethod - def list(cls) -> List[Metric]: - return super(Metric, cls).list() + def list(cls, using: Metabase) -> List[Metric]: + return super(Metric, cls).list(using=using) @classmethod - def get(cls, id: int) -> Metric: - return super(Metric, cls).get(id) + def get(cls, id: int, using: Metabase) -> Metric: + return super(Metric, cls).get(id, using=using) @classmethod def create( cls, + using: Metabase, name: str, table_id: int, definition: dict, @@ -48,6 +50,7 @@ def create( **kwargs ) -> Metric: return super(Metric, cls).create( + using=using, name=name, table_id=table_id, definition=definition, diff --git a/src/metabase/resources/permission_group.py b/src/metabase/resources/permission_group.py index de13346..eaa27d2 100644 --- a/src/metabase/resources/permission_group.py +++ b/src/metabase/resources/permission_group.py @@ -2,6 +2,7 @@ from typing import List +from metabase import Metabase from metabase.resource import ( CreateResource, DeleteResource, @@ -21,31 +22,31 @@ class PermissionGroup( member_count: int @classmethod - def list(cls) -> List[PermissionGroup]: + def list(cls, using: Metabase) -> List[PermissionGroup]: """ Fetch all PermissionsGroups, including a count of the number of :members in that group. You must be a superuser to do this. """ - return super(PermissionGroup, cls).list() + return super(PermissionGroup, cls).list(using=using) @classmethod - def get(cls, id: int) -> PermissionGroup: + def get(cls, id: int, using: Metabase) -> PermissionGroup: """ Fetch the details for a certain permissions group. You must be a superuser to do this. """ - return super(PermissionGroup, cls).get(id) + return super(PermissionGroup, cls).get(id, using=using) @classmethod - def create(cls, name: str, **kwargs) -> PermissionGroup: + def create(cls, using: Metabase, name: str, **kwargs) -> PermissionGroup: """ Create a new PermissionsGroup. You must be a superuser to do this. """ - return super(PermissionGroup, cls).create(name=name, **kwargs) + return super(PermissionGroup, cls).create(using=using, name=name, **kwargs) def update(self, name: str, **kwargs) -> None: """ diff --git a/src/metabase/resources/permission_membership.py b/src/metabase/resources/permission_membership.py index 58b7ac6..dcbc39c 100644 --- a/src/metabase/resources/permission_membership.py +++ b/src/metabase/resources/permission_membership.py @@ -4,6 +4,7 @@ from requests import HTTPError +from metabase import Metabase from metabase.resource import CreateResource, DeleteResource, ListResource @@ -18,7 +19,7 @@ class PermissionMembership(ListResource, CreateResource, DeleteResource): # TODO: allow for bulk updates through /api/permissions/membership/graph @classmethod - def list(cls) -> List[PermissionMembership]: + def list(cls, using: Metabase) -> List[PermissionMembership]: """ Fetch a map describing the group memberships of various users. This map’s format is: @@ -26,21 +27,23 @@ def list(cls) -> List[PermissionMembership]: :group_id }]}. You must be a superuser to do this. """ - response = cls.connection().get(cls.ENDPOINT) + response = using.get(cls.ENDPOINT) all_memberships = [ item for sublist in response.json().values() for item in sublist ] - records = [cls(**record) for record in all_memberships] + records = [cls(_using=using, **record) for record in all_memberships] return records @classmethod - def create(cls, group_id: int, user_id: int, **kwargs) -> PermissionMembership: + def create( + cls, using: Metabase, group_id: int, user_id: int, **kwargs + ) -> PermissionMembership: """ Add a User to a PermissionsGroup. Returns updated list of members belonging to the group. You must be a superuser to do this. """ - response = cls.connection().post( + response = using.post( cls.ENDPOINT, json={"group_id": group_id, "user_id": user_id} ) @@ -50,4 +53,4 @@ def create(cls, group_id: int, user_id: int, **kwargs) -> PermissionMembership: # metabase returns a list of all memberships for the given group_id membership = next(filter(lambda x: x["user_id"] == user_id, response.json())) - return cls(**membership) + return cls(_using=using, **membership) diff --git a/src/metabase/resources/segment.py b/src/metabase/resources/segment.py index 1cd1da7..5998b82 100644 --- a/src/metabase/resources/segment.py +++ b/src/metabase/resources/segment.py @@ -2,6 +2,7 @@ from typing import List +from metabase import Metabase from metabase.missing import MISSING from metabase.resource import CreateResource, GetResource, ListResource, UpdateResource @@ -26,16 +27,17 @@ class Segment(ListResource, CreateResource, GetResource, UpdateResource): created_at: str @classmethod - def list(cls) -> List[Segment]: - return super(Segment, cls).list() + def list(cls, using: Metabase) -> List[Segment]: + return super(Segment, cls).list(using=using) @classmethod - def get(cls, id: int) -> Segment: - return super(Segment, cls).get(id) + def get(cls, id: int, using: Metabase) -> Segment: + return super(Segment, cls).get(id, using=using) @classmethod def create( cls, + using: Metabase, name: str, table_id: int, definition: dict, @@ -43,6 +45,7 @@ def create( **kwargs ) -> Segment: return super(Segment, cls).create( + using=using, name=name, table_id=table_id, definition=definition, diff --git a/src/metabase/resources/table.py b/src/metabase/resources/table.py index 0910c69..7fdeea4 100644 --- a/src/metabase/resources/table.py +++ b/src/metabase/resources/table.py @@ -3,6 +3,7 @@ from enum import Enum from typing import Any, Dict, List +from metabase import Metabase from metabase.missing import MISSING from metabase.resource import GetResource, ListResource, Resource, UpdateResource from metabase.resources.field import Field @@ -60,14 +61,14 @@ class FieldOrder(str, Enum): smart = "smart" @classmethod - def list(cls) -> List[Table]: + def list(cls, using: Metabase) -> List[Table]: """Get all Tables.""" - return super(Table, cls).list() + return super(Table, cls).list(using=using) @classmethod - def get(cls, id: int) -> Table: + def get(cls, id: int, using: Metabase) -> Table: """Get Table with ID.""" - return super(Table, cls).get(id) + return super(Table, cls).get(id, using=using) def update( self, @@ -95,11 +96,9 @@ def update( def fks(self) -> List[dict]: """Get all foreign keys whose destination is a Field that belongs to this Table.""" - return ( - self.connection() - .get(self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/fks") - .json() - ) + return self._using.get( + self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/fks" + ).json() def query_metadata(self) -> Dict[str, Any]: """ @@ -112,23 +111,15 @@ def query_metadata(self) -> Dict[str, Any]: These options are provided for use in the Admin Edit Metadata page. """ - return ( - self.connection() - .get( - self.ENDPOINT - + f"/{getattr(self, self.PRIMARY_KEY)}" - + "/query_metadata" - ) - .json() - ) + return self._using.get( + self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/query_metadata" + ).json() def related(self) -> Dict[str, Any]: """Return related entities.""" - return ( - self.connection() - .get(self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/related") - .json() - ) + return self._using.get( + self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/related" + ).json() def discard_values(self): """ @@ -138,7 +129,7 @@ def discard_values(self): You must be a superuser to do this. """ - self.connection().post( + self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/discard_values" ) @@ -149,18 +140,21 @@ def rescan_values(self): You must be a superuser to do this. """ - self.connection().post( + self._using.post( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/rescan_values" ) def fields(self) -> List[Field]: """Get all Fields associated with this Table..""" - return [Field(**field) for field in self.query_metadata().get("fields")] + return [ + Field(_using=self._using, **field) + for field in self.query_metadata().get("fields") + ] def dimensions(self) -> List[Dimension]: """Get all Dimensions associated with this Table.""" return [ - Dimension(id=id, **dimension) + Dimension(id=id, _using=self._using, **dimension) for id, dimension in self.query_metadata() .get("dimension_options", {}) .items() @@ -168,8 +162,14 @@ def dimensions(self) -> List[Dimension]: def metrics(self) -> List[Metric]: """Get all Metrics associated with this Table.""" - return [Metric(**metric) for metric in self.related().get("metrics")] + return [ + Metric(_using=self._using, **metric) + for metric in self.related().get("metrics") + ] def segments(self) -> List[Segment]: """Get all Segments associated with this Table.""" - return [Segment(**segment) for segment in self.related().get("segments")] + return [ + Segment(_using=self._using, **segment) + for segment in self.related().get("segments") + ] diff --git a/src/metabase/resources/user.py b/src/metabase/resources/user.py index 2cbacc1..3c09ae2 100644 --- a/src/metabase/resources/user.py +++ b/src/metabase/resources/user.py @@ -3,6 +3,7 @@ from datetime import datetime from typing import Any, Dict, List +from metabase import Metabase from metabase.missing import MISSING from metabase.resource import ( CreateResource, @@ -37,7 +38,7 @@ class User(ListResource, CreateResource, GetResource, UpdateResource, DeleteReso updated_at: datetime @classmethod - def list(cls) -> List[User]: + def list(cls, using: Metabase) -> List[User]: """ Fetch a list of Users. By default returns every active user but only active users. @@ -47,13 +48,16 @@ def list(cls) -> List[User]: Takes limit, offset for pagination. Takes query for filtering on first name, last name, email. Also takes group_id, which filters on group id. """ - response = cls.connection().get(cls.ENDPOINT) - records = [cls(**user) for user in response.json().get("data", [])] + response = using.get(cls.ENDPOINT) + records = [ + cls(_using=using, **user) for user in response.json().get("data", []) + ] return records @classmethod def create( cls, + using: Metabase, first_name: str, last_name: str, email: str, @@ -68,6 +72,7 @@ def create( You must be a superuser to do this. """ return super(User, cls).create( + using=using, first_name=first_name, last_name=last_name, email=email, @@ -107,7 +112,7 @@ def delete(self) -> None: def password(self, password: str, old_password: str): """Update a user’s password.""" - return self.connection().put( + return self._using.put( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/password", json={"password": password, "old_password": old_password}, ) @@ -118,7 +123,7 @@ def send_invite(self): You must be a superuser to do this. """ - return self.connection().put( + return self._using.put( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/send_invite" ) @@ -128,6 +133,6 @@ def reactivate(self): You must be a superuser to do this. """ - return self.connection().put( + return self._using.put( self.ENDPOINT + f"/{getattr(self, self.PRIMARY_KEY)}" + "/reactivate" ) diff --git a/tests/resources/test_card.py b/tests/resources/test_card.py index 36c973f..92e2be4 100644 --- a/tests/resources/test_card.py +++ b/tests/resources/test_card.py @@ -10,7 +10,7 @@ def test_import(self): """Ensure Card can be imported from Metabase.""" from metabase import Card - self.assertIsNotNone(Card()) + self.assertIsNotNone(Card(_using=None)) def test_list(self): """Ensure Card.list() returns a list of Card instances.""" @@ -31,9 +31,10 @@ def test_list(self): "graph.metrics": ["count"], }, display="line", + using=self.metabase, ) - cards = Card.list() + cards = Card.list(using=self.metabase) self.assertIsInstance(cards, list) self.assertTrue(len(cards) > 0) @@ -41,7 +42,7 @@ def test_list(self): def test_get(self): """Ensure Card.get() returns a Card instance for a given ID.""" - card = Card.get(1) + card = Card.get(1, using=self.metabase) self.assertIsInstance(card, Card) self.assertEqual(1, card.id) @@ -64,12 +65,15 @@ def test_create(self): "graph.metrics": ["count"], }, display="line", + using=self.metabase, ) self.assertIsInstance(card, Card) self.assertEqual("My Card", card.name) self.assertEqual("line", card.display) - self.assertIsInstance(Card.get(card.id), Card) # instance exists in Metabase + self.assertIsInstance( + Card.get(card.id, using=self.metabase), Card + ) # instance exists in Metabase # teardown card.archive() @@ -93,9 +97,10 @@ def test_update(self): "graph.metrics": ["count"], }, display="line", + using=self.metabase, ) - card = Card.get(1) + card = Card.get(1, using=self.metabase) name = card.name card.update(name="New Name") @@ -104,7 +109,7 @@ def test_update(self): self.assertEqual("New Name", card.name) # assert metabase object is mutated - t = Card.get(card.id) + t = Card.get(card.id, using=self.metabase) self.assertEqual("New Name", t.name) # teardown @@ -129,11 +134,12 @@ def test_archive(self): "graph.metrics": ["count"], }, display="line", + using=self.metabase, ) self.assertIsInstance(card, Card) card.archive() self.assertEqual(True, card.archived) - c = Card.get(card.id) + c = Card.get(card.id, using=self.metabase) self.assertEqual(True, c.archived) diff --git a/tests/resources/test_database.py b/tests/resources/test_database.py index a1afa13..db86415 100644 --- a/tests/resources/test_database.py +++ b/tests/resources/test_database.py @@ -11,11 +11,11 @@ def test_import(self): """Ensure Database can be imported from Metabase.""" from metabase import Database - self.assertIsNotNone(Database()) + self.assertIsNotNone(Database(_using=None)) def test_list(self): """Ensure Database.list() returns a list of Database instances.""" - databases = Database.list() + databases = Database.list(using=self.metabase) self.assertIsInstance(databases, list) self.assertTrue(len(databases) > 0) @@ -23,7 +23,7 @@ def test_list(self): def test_get(self): """Ensure Database.get() returns a Database instance for a given ID.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) self.assertIsInstance(database, Database) self.assertEqual(1, database.id) @@ -36,13 +36,14 @@ def test_create(self): details={ "db": "zip:/app/metabase.jar!/sample-dataset.db;USER=GUEST;PASSWORD=guest" }, + using=self.metabase, ) self.assertIsInstance(database, Database) self.assertEqual("Test", database.name) self.assertEqual("h2", database.engine) self.assertIsInstance( - Database.get(database.id), Database + Database.get(database.id, using=self.metabase), Database ) # instance exists in Metabase # teardown @@ -50,7 +51,7 @@ def test_create(self): def test_update(self): """Ensure Database.update() updates an existing Database in Metabase.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) name = database.name database.update(name="New Name") @@ -59,7 +60,7 @@ def test_update(self): self.assertEqual("New Name", database.name) # assert metabase object is mutated - t = Database.get(database.id) + t = Database.get(database.id, using=self.metabase) self.assertEqual("New Name", t.name) # teardown @@ -74,6 +75,7 @@ def test_delete(self): details={ "db": "zip:/app/metabase.jar!/sample-dataset.db;USER=GUEST;PASSWORD=guest" }, + using=self.metabase, ) self.assertIsInstance(database, Database) @@ -81,11 +83,11 @@ def test_delete(self): # assert metabase object is mutated with self.assertRaises(NotFoundError): - _ = Database.get(database.id) + _ = Database.get(database.id, using=self.metabase) def test_fields(self): """Ensure Database.fields() returns a list of Field instances.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) fields = database.fields() self.assertIsInstance(fields, list) @@ -94,7 +96,7 @@ def test_fields(self): def test_idfields(self): """Ensure Database.idfields() returns a list of Field instances.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) fields = database.idfields() self.assertIsInstance(fields, list) @@ -103,7 +105,7 @@ def test_idfields(self): def test_schemas(self): """Ensure Database.schemas() returns a list of strings.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) schemas = database.schemas() self.assertIsInstance(schemas, list) @@ -112,7 +114,7 @@ def test_schemas(self): def test_tables(self): """Ensure Database.tables() returns a list of Table instances.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) schema = database.schemas()[0] tables = database.tables(schema) @@ -122,28 +124,28 @@ def test_tables(self): def test_discard_values(self): """Ensure Database.discard_values() does not raise an error.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) response = database.discard_values() self.assertEqual(200, response.status_code) def test_rescan_values(self): """Ensure Database.rescan_values() does not raise an error.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) response = database.rescan_values() self.assertEqual(200, response.status_code) def test_sync(self): """Ensure Database.sync() does not raise an error.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) response = database.sync() self.assertEqual(200, response.status_code) def test_sync_schema(self): """Ensure Database.sync_schema() does not raise an error.""" - database = Database.get(1) + database = Database.get(1, using=self.metabase) response = database.sync_schema() self.assertEqual(200, response.status_code) diff --git a/tests/resources/test_dataset.py b/tests/resources/test_dataset.py index 232df67..e66a331 100644 --- a/tests/resources/test_dataset.py +++ b/tests/resources/test_dataset.py @@ -9,7 +9,7 @@ def test_import(self): """Ensure Metric can be imported from Metabase.""" from metabase import Dataset - self.assertIsNotNone(Dataset()) + self.assertIsNotNone(Dataset(_using=None)) def test_create(self): """Ensure Dataset.create() executes a query and returns a Dataset instance with the query results.""" @@ -21,6 +21,7 @@ def test_create(self): "breakout": [["field", 7, {"temporal-unit": "year"}]], "aggregation": [["count"]], }, + using=self.metabase, ) self.assertIsInstance(dataset, Dataset) self.assertIsInstance(dataset.data, Data) @@ -35,6 +36,7 @@ def test_to_pandas(self): "breakout": [["field", 7, {"temporal-unit": "year"}]], "aggregation": [["count"]], }, + using=self.metabase, ) df = dataset.to_pandas() self.assertIsInstance(df, pd.DataFrame) diff --git a/tests/resources/test_field.py b/tests/resources/test_field.py index 223a74c..36f4ae8 100644 --- a/tests/resources/test_field.py +++ b/tests/resources/test_field.py @@ -10,18 +10,18 @@ def test_import(self): """Ensure Field can be imported from Metabase.""" from metabase import Field - self.assertIsNotNone(Field()) + self.assertIsNotNone(Field(_using=None)) def test_get(self): """Ensure Field.get() returns a Field instance for a given ID.""" - field = Field.get(1) + field = Field.get(1, using=self.metabase) self.assertIsInstance(field, Field) self.assertEqual(1, field.id) def test_update(self): """Ensure Field.update() updates an existing Field in Metabase.""" - field = Field.get(1) + field = Field.get(1, using=self.metabase) display_name = field.display_name semantic_type = field.semantic_type @@ -32,7 +32,7 @@ def test_update(self): self.assertEqual(Field.SemanticType.zip_code, field.semantic_type) # assert metabase object is mutated - f = Field.get(field.id) + f = Field.get(field.id, using=self.metabase) self.assertEqual("New Name", f.display_name) self.assertEqual(Field.SemanticType.zip_code, f.semantic_type) @@ -41,7 +41,7 @@ def test_update(self): def test_related(self): """Ensure Field.related() returns a dict.""" - field = Field.get(1) + field = Field.get(1, using=self.metabase) related = field.related() self.assertIsInstance(related, dict) diff --git a/tests/resources/test_metric.py b/tests/resources/test_metric.py index b1b302b..bf0da86 100644 --- a/tests/resources/test_metric.py +++ b/tests/resources/test_metric.py @@ -5,7 +5,7 @@ class MetricTests(IntegrationTestCase): def tearDown(self) -> None: - metrics = Metric.list() + metrics = Metric.list(using=self.metabase) for metric in metrics: metric.archive() @@ -13,7 +13,7 @@ def test_import(self): """Ensure Metric can be imported from Metabase.""" from metabase import Metric - self.assertIsNotNone(Metric()) + self.assertIsNotNone(Metric(_using=None)) def test_list(self): """Ensure Metric.list returns a list of Metric instances.""" @@ -24,6 +24,7 @@ def test_list(self): definition={ "aggregation": [["count"]], }, + using=self.metabase, ) _ = Metric.create( name="My Metric", @@ -31,9 +32,10 @@ def test_list(self): definition={ "aggregation": [["count"]], }, + using=self.metabase, ) - metrics = Metric.list() + metrics = Metric.list(using=self.metabase) self.assertIsInstance(metrics, list) self.assertEqual(2, len(metrics)) @@ -51,15 +53,16 @@ def test_get(self): definition={ "aggregation": [["count"]], }, + using=self.metabase, ) self.assertIsInstance(metric, Metric) - m = Metric.get(metric.id) + m = Metric.get(metric.id, using=self.metabase) self.assertIsInstance(m, Metric) self.assertEqual(metric.id, m.id) with self.assertRaises(NotFoundError): - _ = Metric.get(12345) + _ = Metric.get(12345, using=self.metabase) def test_create(self): """Ensure Metric.create creates a Metric in Metabase and returns a Metric instance.""" @@ -69,6 +72,7 @@ def test_create(self): definition={ "aggregation": [["count"]], }, + using=self.metabase, ) self.assertIsInstance(metric, Metric) @@ -85,6 +89,7 @@ def test_update(self): definition={ "aggregation": [["count"]], }, + using=self.metabase, ) self.assertIsInstance(metric, Metric) @@ -95,7 +100,7 @@ def test_update(self): self.assertEqual("New Name", metric.name) # assert metabase object is mutated - m = Metric.get(metric.id) + m = Metric.get(metric.id, using=self.metabase) self.assertEqual("New Name", m.name) def test_archive(self): @@ -107,6 +112,7 @@ def test_archive(self): definition={ "aggregation": [["count"]], }, + using=self.metabase, ) self.assertIsInstance(metric, Metric) @@ -117,5 +123,5 @@ def test_archive(self): self.assertEqual(True, metric.archived) # assert metabase object is mutated - m = Metric.get(metric.id) + m = Metric.get(metric.id, using=self.metabase) self.assertEqual(True, m.archived) diff --git a/tests/resources/test_permission_group.py b/tests/resources/test_permission_group.py index 3f7c1c5..8f1e66b 100644 --- a/tests/resources/test_permission_group.py +++ b/tests/resources/test_permission_group.py @@ -5,7 +5,7 @@ class PermissionMembershipTests(IntegrationTestCase): def tearDown(self) -> None: - groups = PermissionGroup.list() + groups = PermissionGroup.list(using=self.metabase) for group in groups: if group.id not in (1, 2): # can't delete default groups @@ -15,11 +15,11 @@ def test_import(self): """Ensure PermissionGroup can be imported from Metabase.""" from metabase import PermissionGroup - self.assertIsNotNone(PermissionGroup()) + self.assertIsNotNone(PermissionGroup(_using=None)) def test_list(self): """Ensure PermissionGroup.list returns a list of PermissionGroup instances.""" - groups = PermissionGroup.list() + groups = PermissionGroup.list(using=self.metabase) self.assertIsInstance(groups, list) self.assertEqual(2, len(groups)) # there are 2 default groups in Metabase @@ -31,21 +31,19 @@ def test_get(self): raises a NotFoundError when it does not exist. """ # fixture - group = PermissionGroup.create(name="My Group") + group = PermissionGroup.create(name="My Group", using=self.metabase) self.assertIsInstance(group, PermissionGroup) - g = PermissionGroup.get(group.id) + g = PermissionGroup.get(group.id, using=self.metabase) self.assertIsInstance(g, PermissionGroup) self.assertEqual(group.id, g.id) with self.assertRaises(NotFoundError): - _ = PermissionGroup.get(12345) + _ = PermissionGroup.get(12345, using=self.metabase) def test_create(self): """Ensure PermissionGroup.create creates a Metric in Metabase and returns a PermissionGroup instance.""" - group = PermissionGroup.create( - name="My Group", - ) + group = PermissionGroup.create(name="My Group", using=self.metabase) self.assertIsInstance(group, PermissionGroup) self.assertEqual("My Group", group.name) @@ -53,9 +51,7 @@ def test_create(self): def test_update(self): """Ensure PermissionGroup.update updates an existing PermissionGroup in Metabase.""" # fixture - group = PermissionGroup.create( - name="My Group", - ) + group = PermissionGroup.create(name="My Group", using=self.metabase) self.assertIsInstance(group, PermissionGroup) self.assertEqual("My Group", group.name) @@ -65,15 +61,13 @@ def test_update(self): self.assertEqual("New Name", group.name) # assert metabase object is mutated - m = PermissionGroup.get(group.id) + m = PermissionGroup.get(group.id, using=self.metabase) self.assertEqual("New Name", m.name) def test_delete(self): """Ensure PermissionGroup.delete deletes a PermissionGroup in Metabase.""" # fixture - group = PermissionGroup.create( - name="My Metric", - ) + group = PermissionGroup.create(name="My Metric", using=self.metabase) self.assertIsInstance(group, PermissionGroup) @@ -81,4 +75,4 @@ def test_delete(self): # assert metabase object is mutated with self.assertRaises(NotFoundError): - _ = PermissionGroup.get(group.id) + _ = PermissionGroup.get(group.id, using=self.metabase) diff --git a/tests/resources/test_permission_membership.py b/tests/resources/test_permission_membership.py index 8a90151..dce5af8 100644 --- a/tests/resources/test_permission_membership.py +++ b/tests/resources/test_permission_membership.py @@ -4,13 +4,13 @@ class PermissionMembershipTests(IntegrationTestCase): def tearDown(self) -> None: - memberships = PermissionMembership.list() + memberships = PermissionMembership.list(using=self.metabase) for membership in memberships: if membership.group_id not in (1, 2): # can't delete memberships in the default groups membership.delete() - groups = PermissionGroup.list() + groups = PermissionGroup.list(using=self.metabase) for group in groups: if group.id not in (1, 2): # can't delete default groups @@ -20,19 +20,21 @@ def test_import(self): """Ensure PermissionMembership can be imported from Metabase.""" from metabase import PermissionMembership - self.assertIsNotNone(PermissionMembership()) + self.assertIsNotNone(PermissionMembership(_using=None)) def test_list(self): """Ensure PermissionMembership.list returns a list of PermissionMembership instances.""" - memberships = PermissionMembership.list() + memberships = PermissionMembership.list(using=self.metabase) self.assertIsInstance(memberships, list) self.assertTrue(len(memberships) > 0) self.assertTrue(all([isinstance(m, PermissionMembership) for m in memberships])) def test_create(self): """Ensure PermissionMembership.create creates a Metric in Metabase and returns a PermissionMembership instance.""" - group = PermissionGroup.create(name="My Group") - membership = PermissionMembership.create(group_id=group.id, user_id=1) + group = PermissionGroup.create(name="My Group", using=self.metabase) + membership = PermissionMembership.create( + group_id=group.id, user_id=1, using=self.metabase + ) self.assertIsInstance(membership, PermissionMembership) self.assertEqual(1, membership.user_id) @@ -40,17 +42,19 @@ def test_create(self): def test_delete(self): """Ensure PermissionMembership.delete deletes a PermissionMembership in Metabase.""" # fixture - group = PermissionGroup.create(name="My Group") - membership = PermissionMembership.create(group_id=group.id, user_id=1) + group = PermissionGroup.create(name="My Group", using=self.metabase) + membership = PermissionMembership.create( + group_id=group.id, user_id=1, using=self.metabase + ) self.assertIsInstance(membership, PermissionMembership) self.assertTrue( membership.membership_id - in [m.membership_id for m in PermissionMembership.list()] + in [m.membership_id for m in PermissionMembership.list(using=self.metabase)] ) membership.delete() self.assertFalse( membership.membership_id - in [m.membership_id for m in PermissionMembership.list()] + in [m.membership_id for m in PermissionMembership.list(using=self.metabase)] ) diff --git a/tests/resources/test_segment.py b/tests/resources/test_segment.py index 4dd7a55..d159514 100644 --- a/tests/resources/test_segment.py +++ b/tests/resources/test_segment.py @@ -5,7 +5,7 @@ class SegmentTests(IntegrationTestCase): def tearDown(self) -> None: - segments = Segment.list() + segments = Segment.list(using=self.metabase) for segment in segments: segment.archive() @@ -13,7 +13,7 @@ def test_import(self): """Ensure Segment can be imported from Metabase.""" from metabase import Segment - self.assertIsNotNone(Segment()) + self.assertIsNotNone(Segment(_using=None)) def test_list(self): """Ensure Segment.list returns a list of Segment instances.""" @@ -24,6 +24,7 @@ def test_list(self): definition={ "filter": ["=", ["field", 1, None], 0], }, + using=self.metabase, ) _ = Segment.create( name="My Segment", @@ -31,9 +32,10 @@ def test_list(self): definition={ "filter": ["=", ["field", 1, None], 0], }, + using=self.metabase, ) - segments = Segment.list() + segments = Segment.list(using=self.metabase) self.assertIsInstance(segments, list) self.assertEqual(2, len(segments)) @@ -51,15 +53,16 @@ def test_get(self): definition={ "filter": ["=", ["field", 1, None], 0], }, + using=self.metabase, ) self.assertIsInstance(segment, Segment) - m = Segment.get(segment.id) + m = Segment.get(segment.id, using=self.metabase) self.assertIsInstance(m, Segment) self.assertEqual(segment.id, m.id) with self.assertRaises(NotFoundError): - _ = Segment.get(12345) + _ = Segment.get(12345, using=self.metabase) def test_create(self): """Ensure Segment.create creates a Segment in Metabase and returns a Segment instance.""" @@ -69,6 +72,7 @@ def test_create(self): definition={ "filter": ["=", ["field", 1, None], 0], }, + using=self.metabase, ) self.assertIsInstance(segment, Segment) @@ -85,6 +89,7 @@ def test_update(self): definition={ "filter": ["=", ["field", 1, None], 0], }, + using=self.metabase, ) self.assertIsInstance(segment, Segment) @@ -95,7 +100,7 @@ def test_update(self): self.assertEqual("New Name", segment.name) # assert metabase object is mutated - m = Segment.get(segment.id) + m = Segment.get(segment.id, using=self.metabase) self.assertEqual("New Name", m.name) def test_archive(self): @@ -107,6 +112,7 @@ def test_archive(self): definition={ "filter": ["=", ["field", 1, None], 0], }, + using=self.metabase, ) self.assertIsInstance(segment, Segment) @@ -117,5 +123,5 @@ def test_archive(self): self.assertEqual(True, segment.archived) # assert metabase object is mutated - m = Segment.get(segment.id) + m = Segment.get(segment.id, using=self.metabase) self.assertEqual(True, m.archived) diff --git a/tests/resources/test_table.py b/tests/resources/test_table.py index 14ca8f7..230abc4 100644 --- a/tests/resources/test_table.py +++ b/tests/resources/test_table.py @@ -12,11 +12,11 @@ def test_import(self): """Ensure Table can be imported from Metabase.""" from metabase import Table - self.assertIsNotNone(Table()) + self.assertIsNotNone(Table(_using=None)) def test_list(self): """Ensure Table.list() returns a list of Table instances.""" - tables = Table.list() + tables = Table.list(using=self.metabase) self.assertIsInstance(tables, list) self.assertTrue(len(tables) > 0) @@ -24,14 +24,14 @@ def test_list(self): def test_get(self): """Ensure Table.get() returns a Table instance for a given ID.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) self.assertIsInstance(table, Table) self.assertEqual(1, table.id) def test_update(self): """Ensure Table.update() updates an existing Table in Metabase.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) display_name = table.display_name table.update(display_name="New Name") @@ -40,7 +40,7 @@ def test_update(self): self.assertEqual("New Name", table.display_name) # assert metabase object is mutated - t = Table.get(table.id) + t = Table.get(table.id, using=self.metabase) self.assertEqual("New Name", t.display_name) # teardown @@ -48,7 +48,7 @@ def test_update(self): def test_foreign_keys(self): """Ensure Table.fks() returns a list of foreign keys as dict.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) fks = table.fks() self.assertIsInstance(fks, list) @@ -57,14 +57,14 @@ def test_foreign_keys(self): def test_query_metadata(self): """Ensure Table.query_metadata() returns a dict.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) query_metadata = table.query_metadata() self.assertIsInstance(query_metadata, dict) def test_related(self): """Ensure Table.related() returns a dict.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) related = table.related() self.assertIsInstance(related, dict) @@ -79,7 +79,7 @@ def test_rescan_values(self): def test_fields(self): """Ensure Table.fields() returns a list of Field instances.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) fields = table.fields() self.assertIsInstance(fields, list) @@ -88,7 +88,7 @@ def test_fields(self): def test_dimensions(self): """Ensure Table.dimensions() returns a list of Dimension instances.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) dimensions = table.dimensions() self.assertIsInstance(dimensions, list) @@ -97,7 +97,7 @@ def test_dimensions(self): def test_metrics(self): """Ensure Table.metrics() returns a list of Metric instances.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) metrics = table.metrics() self.assertIsInstance(metrics, list) @@ -110,6 +110,7 @@ def test_metrics(self): definition={ "aggregation": [["count"]], }, + using=self.metabase, ) metrics = table.metrics() @@ -122,7 +123,7 @@ def test_metrics(self): def test_segments(self): """Ensure Table.segments() returns a list of Segment instances.""" - table = Table.get(1) + table = Table.get(1, using=self.metabase) segments = table.segments() self.assertIsInstance(segments, list) @@ -135,6 +136,7 @@ def test_segments(self): definition={ "filter": ["=", ["field", 1, None], 0], }, + using=self.metabase, ) segments = table.segments() diff --git a/tests/resources/test_user.py b/tests/resources/test_user.py index 4328471..d818c38 100644 --- a/tests/resources/test_user.py +++ b/tests/resources/test_user.py @@ -7,7 +7,7 @@ class UserTests(IntegrationTestCase): def tearDown(self) -> None: - users = User.list() + users = User.list(using=self.metabase) for user in users: if user.id != 1: user.delete() @@ -16,7 +16,7 @@ def test_import(self): """Ensure User can be imported from Metabase.""" from metabase import User - self.assertIsNotNone(User()) + self.assertIsNotNone(User(_using=None)) def test_get(self): """ @@ -29,21 +29,26 @@ def test_get(self): last_name="Test", email=f"{randint(2, 10000)}@example.com", password="example123", + using=self.metabase, ) self.assertIsInstance(user, User) - u = User.get(user.id) + u = User.get(user.id, using=self.metabase) self.assertIsInstance(u, User) self.assertEqual(user.id, u.id) with self.assertRaises(NotFoundError): - _ = User.get(12345) + _ = User.get(12345, using=self.metabase) def test_create(self): """Ensure User.create() creates a User in Metabase and returns a User instance.""" email = f"{randint(2, 10000)}@example.com" user = User.create( - first_name="Test", last_name="Test", email=email, password="example123" + first_name="Test", + last_name="Test", + email=email, + password="example123", + using=self.metabase, ) self.assertIsInstance(user, User) @@ -59,6 +64,7 @@ def test_update(self): last_name="Test", email=f"{randint(2, 10000)}@example.com", password="example123", + using=self.metabase, ) self.assertIsInstance(user, User) @@ -69,7 +75,7 @@ def test_update(self): self.assertEqual("Test1", user.first_name) # assert metabase object is mutated - u = User.get(user.id) + u = User.get(user.id, using=self.metabase) self.assertEqual("Test1", u.first_name) def test_delete(self): @@ -80,6 +86,7 @@ def test_delete(self): last_name="Test", email=f"{randint(2, 10000)}@example.com", password="example123", + using=self.metabase, ) self.assertIsInstance(user, User) @@ -87,4 +94,4 @@ def test_delete(self): # assert metabase object is mutated with self.assertRaises(NotFoundError): - _ = User.get(user.id) + _ = User.get(user.id, using=self.metabase) diff --git a/tests/test_metabase.py b/tests/test_metabase.py index 34f576e..57e0631 100644 --- a/tests/test_metabase.py +++ b/tests/test_metabase.py @@ -6,15 +6,6 @@ class MetabaseTests(TestCase): - def test_singleton(self): - """Ensure Metabase acts as a singleton; the same instance is always returned when instantiated.""" - metabase = Metabase(host="", user="", password="") - metabase1 = Metabase() - - self.assertEqual(metabase, metabase1) - self.assertEqual(metabase.host, metabase1.host) - self.assertEqual(Metabase(), Metabase()) - def test_host(self): """Ensure Metabase.host adds https:// and trims trailing /.""" metabase = Metabase(host="example.com/", user="", password="") diff --git a/tests/test_resource.py b/tests/test_resource.py index 055ef9e..7eab526 100644 --- a/tests/test_resource.py +++ b/tests/test_resource.py @@ -2,7 +2,6 @@ from requests import HTTPError -from metabase import Metabase from metabase.exceptions import NotFoundError from metabase.missing import MISSING from metabase.resource import ( @@ -19,7 +18,7 @@ class ResourceTests(IntegrationTestCase): def test_resource_initializes_all_attributes(self): """Ensure Resource accepts arbitrary attributes when initializing an instance.""" - resource = Resource(a="a", b="b") + resource = Resource(a="a", b="b", _using=None) self.assertEqual("a", resource.a) self.assertEqual("b", resource.b) @@ -31,17 +30,12 @@ def test_resource_initializes_all_attributes(self): def test_repr(self): """Ensure Resource repr prints all class attributes with the PRIMARY_KEY first, if any.""" - resource = Resource(a="a", b="b", id=1) + resource = Resource(a="a", b="b", id=1, _using=None) self.assertEqual("Resource(id=1, a=a, b=b)", resource.__repr__()) resource.PRIMARY_KEY = None self.assertEqual("Resource(a=a, b=b, id=1)", resource.__repr__()) - def test_connection(self): - """Ensure Resource.connection() returns an instance of Metabase.""" - resource = Resource() - self.assertIsInstance(resource.connection(), Metabase) - class ListResourceTests(IntegrationTestCase): def test_list(self): @@ -51,7 +45,7 @@ class Setting(ListResource): ENDPOINT = "/api/setting" PRIMARY_KEY = None - settings = Setting.list() + settings = Setting.list(using=self.metabase) self.assertIsInstance(settings, list) self.assertTrue(all([isinstance(s, Setting) for s in settings])) @@ -63,7 +57,7 @@ def test_get(self): class User(GetResource): ENDPOINT = "/api/user" - user = User.get(1) + user = User.get(1, using=self.metabase) self.assertIsInstance(user, User) def test_get_404(self): @@ -73,7 +67,7 @@ class User(GetResource): ENDPOINT = "/api/user" with self.assertRaises(NotFoundError): - user = User.get(1234) + user = User.get(1234, using=self.metabase) class CreateResourceTests(IntegrationTestCase): @@ -83,9 +77,13 @@ def test_create(self): class Collection(CreateResource, GetResource): ENDPOINT = "/api/collection" - collection = Collection.create(name="My Collection", color="#123456") + collection = Collection.create( + name="My Collection", color="#123456", using=self.metabase + ) self.assertIsInstance(collection, Collection) - self.assertIsNotNone(Collection.get(collection.id)) # metabase was updated + self.assertIsNotNone( + Collection.get(collection.id, using=self.metabase) + ) # metabase was updated class UpdateResourceTests(IntegrationTestCase): @@ -96,15 +94,19 @@ class Collection(CreateResource, GetResource, UpdateResource): ENDPOINT = "/api/collection" # fixture - collection = Collection.create(name="My Collection", color="#123456") + collection = Collection.create( + name="My Collection", color="#123456", using=self.metabase + ) self.assertIsInstance(collection, Collection) - self.assertIsNotNone(Collection.get(collection.id)) + self.assertIsNotNone(Collection.get(collection.id, using=self.metabase)) collection.update(name="My New Collection") self.assertEqual("My New Collection", collection.name) # metabase was updated - self.assertEqual("My New Collection", Collection.get(collection.id).name) + self.assertEqual( + "My New Collection", Collection.get(collection.id, using=self.metabase).name + ) def test_update_missing(self): """Ensure UpdateResource.update() ignores arguments equal to MISSING.""" @@ -121,7 +123,7 @@ class Collection(UpdateResource): for kwargs, expected in test_matrix: with patch("metabase.resource.Metabase.put") as mock: try: - Collection(id=1).update(**kwargs) + Collection(id=1, _using=self.metabase).update(**kwargs) except HTTPError: pass @@ -139,12 +141,12 @@ class Group(CreateResource, GetResource, DeleteResource): ENDPOINT = "/api/permissions/group" PRIMARY_KEY = "id" - group = Group.create(name="My Group 4") + group = Group.create(name="My Group 4", using=self.metabase) self.assertIsNotNone(group) - self.assertIsNotNone(Group.get(group.id)) + self.assertIsNotNone(Group.get(group.id, using=self.metabase)) group.delete() with self.assertRaises(NotFoundError): - Group.get(group.id) + Group.get(group.id, using=self.metabase)